Compare commits

...

330 Commits

Author SHA1 Message Date
Roberto Viola
e48af4e864 Update main.yml 2023-07-20 17:39:50 +02:00
Roberto Viola
e990a27f65 Update main.yml 2023-07-20 16:15:17 +02:00
Roberto Viola
4c88304be0 Update main.yml 2023-07-20 16:14:21 +02:00
Roberto Viola
4c1d39d68c Update main.yml 2023-07-20 16:12:38 +02:00
Roberto Viola
efc92f72b2 Update main.yml 2023-07-20 14:37:13 +02:00
Roberto Viola
424e21a8fa Update main.yml 2023-07-20 14:03:14 +02:00
Roberto Viola
51bc2ffb48 Update main.yml 2023-07-20 12:00:28 +02:00
Roberto Viola
7cfd1ba93b Update main.yml 2023-07-20 11:58:34 +02:00
Roberto Viola
c01e5ccb14 Update main.yml 2023-07-20 11:49:08 +02:00
Roberto Viola
dd495f1a76 Merge branch 'master' into android_CI_googleplay 2023-07-20 11:48:52 +02:00
Roberto Viola
458c44758e Android QT Jars patched (#1575)
* Add files via upload

* adding only bluetooth one
2023-07-20 11:45:30 +02:00
Roberto Viola
78e3a33596 Update main.yml 2023-07-20 11:23:17 +02:00
Roberto Viola
77a9fc718a Update main.yml 2023-07-20 11:13:54 +02:00
Roberto Viola
be12859343 No charts when using floating window #1565 2023-07-19 09:53:21 +02:00
Roberto Viola
d201919b55 HR on iPad issue #1529 2023-07-19 09:38:07 +02:00
Roberto Viola
138a42c2e6 fixing CI build 2023-07-18 16:29:08 +02:00
Roberto Viola
bbe69f3f60 fixing build error 2023-07-18 16:02:50 +02:00
Roberto Viola
b95b3a5018 adding gears to wahookickrsnapbike as did for tacxneo
b443b03d49
2023-07-18 15:54:48 +02:00
Roberto Viola
fb0cbb74a5 adding smtp server info on the bottom of the email 2023-07-18 14:28:54 +02:00
Roberto Viola
deed6019ab adding restore purchase button for iOS guidelines 2023-07-18 14:28:33 +02:00
Roberto Viola
7636f768f1 pro form tour de france no reading #1560 (#1566)
* init and update wrote. need to check the force resistance and inclination and read metrics

* finalizing
2023-07-17 15:54:27 +02:00
Roberto Viola
cdf8a95e30 PaddleOCR for Zwift Workout OCR on Windows #1511 2023-07-14 07:39:12 +02:00
Roberto Viola
13389afe77 PaddleOCR for Zwift Workout OCR on Windows #1511 2023-07-14 07:36:16 +02:00
Roberto Viola
8acfb6b764 PaddleOCR for Zwift Workout OCR on Windows #1511 2023-07-14 07:35:13 +02:00
Roberto Viola
4244ce79a0 Ability to play a video in sync with ZWO training file #1562 2023-07-13 20:48:35 +02:00
Roberto Viola
907e96330f version 2.13.97 2023-07-13 19:25:51 +02:00
Roberto Viola
35136be5b9 Ability to play a video in sync with ZWO training file #1562 2023-07-13 19:00:40 +02:00
Roberto Viola
6cd33f2ff9 Ability to play a video in sync with ZWO training file #1562 2023-07-13 17:21:40 +02:00
Roberto Viola
7e52925242 zwift settings visible only on PC 2023-07-13 16:31:57 +02:00
Roberto Viola
98971bf036 Domyos Treadmill Randomly Send Speed = 0 #1567 2023-07-13 16:28:33 +02:00
Roberto Viola
51e97321ac PaddleOCR for Zwift Workout OCR on Windows #1511 2023-07-13 14:22:02 +02:00
Roberto Viola
d959c0bea2 version 2.13.96 2023-07-13 13:26:56 +02:00
Roberto Viola
875f283984 Ability to play a video in sync with ZWO training file #1562 (#1563)
* to be tested

* it's working!
2023-07-12 23:13:48 +02:00
Roberto Viola
b4f378a8e9 PaddleOCR for Zwift Workout OCR on Windows #1511 2023-07-11 17:03:56 +02:00
Roberto Viola
22e50a7600 PaddleOCR for Zwift Workout OCR on Windows #1511 2023-07-11 13:52:02 +02:00
Roberto Viola
30f3b47a8c fs5i nordick track more realistic ride when running with Rouvy or Zwift #1345 gewahr started this conversation in General fs5i nordick track more realistic ride when running with Rouvy or Zwift #1345 2023-07-11 13:45:33 +02:00
Roberto Viola
103f1675e6 fixing CI android due to USB library (#1547)
* Update build.gradle

* Update main.yml

* Update build.gradle

* Revert "Update main.yml"

This reverts commit 5b232904b1.

* Revert "Update build.gradle"

This reverts commit e961bac22d.
2023-07-11 13:20:37 +02:00
Roberto Viola
db7bc008e4 Training programs UI improvement #1537 2023-07-11 10:52:08 +02:00
Roberto Viola
e634348d75 Life Fitness Elliptical #1554 2023-07-10 08:21:41 +02:00
Roberto Viola
8956957e4d Merge branch 'master' of https://github.com/cagnulein/qdomyos-zwift 2023-07-10 08:06:30 +02:00
Roberto Viola
f79b0074a8 version 2.13.95 2023-07-06 11:19:27 +02:00
Roberto Viola
34abdab013 Sync workout data from android to apple (issue #1551) (#1552)
* first test, doesn't work on android yet

* first test on android

* hr from apple watch to android!
2023-07-06 11:17:11 +02:00
Roberto Viola
b741378a0e qzlogo added as watermark to watt badge 2023-07-06 11:15:51 +02:00
Roberto Viola
5404a68689 version 2.13.94 2023-07-05 20:49:31 +02:00
Roberto Viola
73bc5691e8 Fixed Speed over ANT+: tested on garmin edge 530 #1550 2023-07-05 20:48:10 +02:00
Roberto Viola
de42318370 Fixed Speed over ANT+: tested on garmin edge 530 #1550 2023-07-05 20:31:14 +02:00
Roberto Viola
61acaf033a peloton resistance instead of resistance in the watt badge 2023-07-05 19:34:19 +02:00
Roberto Viola
cd2592b14e fixing miles on badge 2023-07-05 19:29:55 +02:00
Roberto Viola
b0ef38885b ANT+ not working (Issue #1548) 2023-07-05 11:55:08 +02:00
Roberto Viola
34a3e1067d version 2.13.92 2023-07-04 20:28:02 +02:00
Roberto Viola
b084afea11 fixing crash on echelon rower 2023-07-04 19:31:50 +02:00
Roberto Viola
46eb6b3776 ANT+ not working (Issue #1548) 2023-07-04 19:12:54 +02:00
Roberto Viola
23d646848e Watt badge by Email (#1545)
* I have to verifiy if the image works

* Update qml.qrc
2023-07-04 19:04:59 +02:00
Roberto Viola
e78d4565bc Merge branch 'master' of https://github.com/cagnulein/qdomyos-zwift 2023-07-04 16:15:53 +02:00
Roberto Viola
9540bff975 PaddleOCR for Zwift Workout OCR on Windows (#1511)
* Update qzsettings.h

* Create zwift-workout.py

* ready to test!

* Update main.yml

* Update windows_zwift_workout_paddleocr_thread.cpp

* disabling Npu

* Update zwift-workout.py

* Update zwift-incline.py

* preventing conficts in the settings
2023-07-04 15:38:33 +02:00
Roberto Viola
4d5db2e3b3 workoutNameBasedOnBluetoothDevice function added 2023-07-04 09:48:46 +02:00
Roberto Viola
20027b914e 2.13.91 2023-07-04 08:08:50 +02:00
Andrea Gelmini
5764efd487 Fix typos (#1542)
* Fix typos

* Fix typo

* Fix typo

* Fix typo

* Update strydrunpowersensor.cpp

---------

Co-authored-by: Roberto Viola <Cagnulein@gmail.com>
2023-07-04 07:59:11 +02:00
Roberto Viola
c427c72726 Amazon App Store 64 bit compatibility #1328 (#1544)
* trying renaming libs

https://stackoverflow.com/questions/49402451/gradle-task-to-rename-file

* Update main.yml

* Update build.gradle

* Update build.gradle

* Update build.gradle

* Update build.gradle

* fixing for merge it

* fixing!

* Update build.gradle
2023-07-04 07:58:02 +02:00
Roberto Viola
41be14bb8a target cadence added to the overridable metrics for peloton 2023-07-03 19:07:23 +02:00
Roberto Viola
2fcd6eb310 FTMS treadmill: pause handled 2023-07-03 14:51:29 +02:00
Roberto Viola
656d404582 Merge branch 'master' of https://github.com/cagnulein/qdomyos-zwift 2023-07-01 22:02:26 +02:00
Roberto Viola
548bdeb5e4 Adding Pace to Virtual Rower #1540 2023-07-01 22:02:08 +02:00
Roberto Viola
eaa5fca1fe Create "Peloton-Like" Summary Page in addition to Charts (Issue #517) 2023-06-30 23:01:46 +02:00
Roberto Viola
c9778f918d Adding Pace to Virtual Rower #1540 2023-06-30 22:29:52 +02:00
Roberto Viola
de17acdfcf fixing chartjs image on iOS 2023-06-30 21:58:13 +02:00
Roberto Viola
3f16b7d146 version 2.13.87 2023-06-29 13:52:39 +02:00
Roberto Viola
881e6db650 Android Billing v5 requirements from 11/1/2023 #1512 2023-06-29 13:51:39 +02:00
Roberto Viola
d27bccaea5 Training programs UI improvement #1537 2023-06-29 09:02:09 +02:00
Roberto Viola
afde8ad8d5 Adding Pace to Virtual Rower #1540 2023-06-28 23:18:31 +02:00
Roberto Viola
d8d0613f6d Create "Peloton-Like" Summary Page in addition to Charts #517 (#1533)
* drafting

* creating summary

* i need to work to the image

* ready to test

* Update qml.qrc

* fixing

* preparing for release
2023-06-28 21:59:29 +02:00
Roberto Viola
e255267116 fixed speed over 12.7 on the ziprotreadmill 2023-06-28 21:30:06 +02:00
Roberto Viola
e7e79b1816 zip windows release to improve CI performance (#1539)
* zip windows release to improve CI performance

* Update main.yml
2023-06-28 14:19:12 +02:00
Roberto Viola
df09bd2a9c Windows CI with and without python (#1513)
* Update main.yml

* Update main.yml

* Update main.yml

* Update main.yml

* Update main.yml

* Update main.yml

* Update main.yml
2023-06-28 13:50:51 +02:00
Roberto Viola
7ae17516f1 Create CODE_OF_CONDUCT.md 2023-06-28 13:24:18 +02:00
Roberto Viola
4f53e28cc4 using QT cache for CI (#1538)
* Update main.yml

* Update main.yml
2023-06-28 12:21:26 +02:00
Roberto Viola
08c9869c84 VirtuFit Etappe 2.0i Spinbike ERG Table #1526 2023-06-27 22:43:08 +02:00
Roberto Viola
86bd39b370 BH NLS12 ELLIPTICAL #1393 2023-06-27 11:18:55 +02:00
Roberto Viola
1e68328c0f Training programs UI improvement #1537 2023-06-27 10:13:57 +02:00
Roberto Viola
81d8950bb6 VirtuFit Etappe 2.0i Spinbike ERG Table #1526 2023-06-27 08:56:24 +02:00
Andrea Gelmini
df109a620e Fix typos (#1536) 2023-06-26 11:28:24 +02:00
Roberto Viola
fdc3e4166a Nordic Track S22i 10x expected Watt [BUG] (Issue #1534) 2023-06-22 23:26:10 +02:00
Roberto Viola
144472c57f VirtuFit Etappe 2.0i Spinbike ERG Table #1526 2023-06-22 23:14:49 +02:00
Roberto Viola
d23b36f267 BH NLS12 ELLIPTICAL #1393 2023-06-22 10:08:00 +02:00
Roberto Viola
47ed429773 Wahoo Kickr Headwind #1281 2023-06-22 09:52:10 +02:00
Roberto Viola
f8a09dc301 iOS Crash when bluetooth thread is busy #1530 2023-06-22 09:50:24 +02:00
Roberto Viola
c1b6b0e175 Rowing Concept2 Pm3, Pm4 (Bluetooth) #1486 2023-06-22 09:46:30 +02:00
Roberto Viola
d2e007fb43 Auto-Resistance Adjustment for NordicTrack VR25 #1532 2023-06-22 08:25:10 +02:00
Roberto Viola
589dd85678 Auto-Resistance Adjustment for NordicTrack VR25 #1532 2023-06-21 16:09:24 +02:00
Roberto Viola
4f4c6cebf1 added the first draft of a ESP32 app 2023-06-21 11:21:45 +02:00
Roberto Viola
1688a571af android version 2.13.83 2023-06-20 09:32:58 +02:00
Roberto Viola
018f96d243 Pro-form SB - Model # PFEVEX72917S #1507 (#1514)
* init and write done, i don't see any resistance writing in the hci snoof

* Update proformbike.cpp
2023-06-20 09:31:21 +02:00
Roberto Viola
428d7fee83 A setting to allow QZ to read data as KM rather than Miles on Echelon Stride Treadmill (Issue #1528) 2023-06-19 22:16:32 +02:00
Roberto Viola
ffb09bf78d Rowing Concept2 Pm3, Pm4 (Bluetooth) #1486 2023-06-19 22:06:42 +02:00
Roberto Viola
3a94929584 Rowing Concept2 Pm3, Pm4 (Bluetooth) #1486 2023-06-19 17:16:31 +02:00
Roberto Viola
fea04b29a4 v. 2.13.80 2023-06-16 10:15:44 +02:00
Roberto Viola
f7145710af VirtuFit Etappe 2.0i Spinbike ERG Table #1526 2023-06-16 09:31:13 +02:00
Roberto Viola
e3ef341e60 Rowing Concept2 Pm3, Pm4 (Bluetooth) #1486 2023-06-16 09:02:31 +02:00
Roberto Viola
b097e0898e Volume keys not working on android even if the volume gears setting is disabled #1524 (#1525)
* Update main.qml

* fixed!
2023-06-16 07:13:28 +02:00
Roberto Viola
8237c3c862 Merge branch 'master' of https://github.com/cagnulein/qdomyos-zwift 2023-06-15 21:58:39 +02:00
Roberto Viola
6d6bad02db Peloton workout doesnt start on fake device #1522 2023-06-15 21:58:09 +02:00
Roberto Viola
9dd25f0d69 Rowing Concept2 Pm3, Pm4 (Bluetooth) #1486 2023-06-15 08:07:00 +02:00
Roberto Viola
c84e16aed9 build 590 2023-06-14 21:00:46 +02:00
Roberto Viola
f10e68f47b Peloton workout doesnt start on fake device #1522 2023-06-14 15:40:18 +02:00
Roberto Viola
07111d5a9e Support for Ultrasport F-Bike 400B #690 2023-06-14 14:06:31 +02:00
Roberto Viola
77a4d4224a NordicTrack X11i - watt value takes on huge value when incline level set to "-6%" #52
https://github.com/cagnulein/QZCompanionNordictrackTreadmill/issues/52
2023-06-14 11:54:55 +02:00
Roberto Viola
bda145a29e Kickr Snap #585 2023-06-14 11:17:41 +02:00
Roberto Viola
54799c3519 Revert "Peloton Rowing with Concept 2 #1481"
This reverts commit 90469409b7.
2023-06-13 21:48:05 +02:00
Roberto Viola
1580471db8 Update csaferower.cpp 2023-06-12 13:19:52 +02:00
Roberto Viola
0b918f1b44 Rowing Concept2 Pm3, Pm4 (Bluetooth) (Issue #1486) 2023-06-12 13:08:30 +02:00
Roberto Viola
a13719b0a0 Merge branch 'master' of https://github.com/cagnulein/qdomyos-zwift 2023-06-12 11:43:15 +02:00
Roberto Viola
90469409b7 Peloton Rowing with Concept 2 #1481 2023-06-12 11:43:02 +02:00
Roberto Viola
e3474fa844 Update CSafeRowerUSBHID.java 2023-06-11 16:30:26 +02:00
Roberto Viola
2da438778a Rowing Concept2 Pm3, Pm4 (Bluetooth) #1486 2023-06-11 15:54:10 +02:00
Roberto Viola
2cf61c2ccf fitplusbike with and without response 2023-06-11 12:10:57 +02:00
Roberto Viola
6b8b1c2f68 fixing android build error 2023-06-10 20:41:31 +02:00
Roberto Viola
85b0bd5f74 Domyos EL500 elliptical Cadence settings (Issue #1519) 2023-06-10 20:31:42 +02:00
Roberto Viola
bf53671dc7 Rowing Concept2 Pm3, Pm4 (Bluetooth) (Issue #1486) 2023-06-10 20:27:08 +02:00
Roberto Viola
86f4bdddd7 Rowing Concept2 Pm3, Pm4 (Bluetooth) #1486 2023-06-09 10:27:38 +02:00
Roberto Viola
1096b08fdd Use Peloton workout name in fit file #1502 2023-06-09 09:37:11 +02:00
Roberto Viola
5d1b115645 Usbhid #1486 (#1510)
* Revert "fixing android build"

This reverts commit c44f576876.

* Revert "Rowing concept2 pm3, pm4 (bluetooth) #1486 (#1505)"

This reverts commit 71647a8406.

* usb hid first commit

* fixing android build

* Update CSafeRowerUSBHID.java
2023-06-08 11:11:01 +02:00
Roberto Viola
094c5a838d Use Peloton workout name in fit file #1502 2023-06-08 10:15:01 +02:00
Roberto Viola
2488cc8758 PaddleOCR for Zwift OCR on Windows (#1438)
* Update main.yml

* Update main.yml

* Update main.yml

* Update main.yml

* Update main.yml

* Update main.yml

* Update main.yml

* Update main.yml

* Update main.yml

* Update main.yml

* Update main.yml

* Update main.yml

* Update main.yml

* Update main.yml

* Update main.yml

* Update main.yml

* Update main.yml

* Update main.yml

* Update main.yml

* Update main.yml

* Update main.yml

* Update main.yml

* Update main.yml

* Update main.yml

* Update main.yml

* very raw implementation of the python script

https://github.com/victorypoint/iFit-Wolf3/blob/main/process-image.py

* Update windows_zwift_incline_paddleocr_thread.h

* fixing path

* use signal

* fixing lag on debug prints

* fixing chinese file url

* Update zwift-incline.py

* Update zwift-incline.py

* Update main.yml

* Update zwift-incline.py
2023-06-08 10:03:47 +02:00
Roberto Viola
8084b9f06b Rowing Concept2 Pm3, Pm4 (Bluetooth) #1486 2023-06-07 21:42:14 +02:00
Roberto Viola
8b48707dfb Powerzone line and zones not showing #1509 2023-06-07 21:31:00 +02:00
Roberto Viola
0ad679e2f8 Rowing Concept2 Pm3, Pm4 (Bluetooth) #1486 2023-06-07 21:20:05 +02:00
Roberto Viola
33a1202f5f BH NLS12 ELLIPTICAL #1393 2023-06-06 16:20:29 +02:00
Roberto Viola
776aee4902 Merge branch 'master' of https://github.com/cagnulein/qdomyos-zwift 2023-06-06 14:19:51 +02:00
Roberto Viola
c44f576876 fixing android build 2023-06-06 14:19:47 +02:00
Roberto Viola
a723dce8fc fixed simulator don't show up on xcode 2023-06-06 10:53:56 +02:00
Roberto Viola
7329389ffc 2.13.72 2023-06-06 09:17:02 +02:00
Roberto Viola
71647a8406 Rowing concept2 pm3, pm4 (bluetooth) #1486 (#1505)
* builds!

* Update Usbserial.java
2023-06-06 09:15:57 +02:00
Roberto Viola
669a99e6cd Peloton Rowing with Concept 2 #1481 2023-06-05 22:29:23 +02:00
Roberto Viola
49b0883e26 STOP , PAUSE , START buttons do not function on FTMS treadmill (Issue #1503) 2023-06-05 22:13:53 +02:00
Roberto Viola
ec13911855 Auto Sync Not Working On Google TV with IPAD ios #1441
https://github.com/cagnulein/qdomyos-zwift/issues/1441#issuecomment-1575613785
2023-06-05 09:01:47 +02:00
Roberto Viola
5b7422cff0 Use Peloton workout name in fit file #1502 2023-06-05 08:26:30 +02:00
Roberto Viola
ee7b1ca1d5 STOP , PAUSE , START buttons do not function on FTMS treadmill #1503 2023-06-05 08:17:32 +02:00
Roberto Viola
b588037651 Rowing Concept2 Pm3, Pm4 (Bluetooth) #1486
reverting and start a separate branch
2023-06-04 17:03:54 +02:00
Roberto Viola
5a19c314ba Rowing Concept2 Pm3, Pm4 (Bluetooth) #1486 2023-06-04 16:56:41 +02:00
Roberto Viola
4e06af6200 Use Peloton workout name in fit file #1502 2023-06-04 16:47:12 +02:00
Roberto Viola
b6ffdb7145 Rowing Concept2 Pm3, Pm4 (Bluetooth) #1486 2023-06-04 16:35:32 +02:00
Roberto Viola
02c7c2ff2a Peloton Rowing with Concept 2 (Issue #1481) 2023-06-04 10:14:51 +02:00
Roberto Viola
6369194167 Peloton Rowing with Concept 2 #1481 2023-06-04 08:36:15 +02:00
Roberto Viola
fd8984f2ca 2.13.67 2023-06-03 16:16:46 +02:00
Roberto Viola
328b2cadc1 Peloton Rowing with Concept 2 #1481 2023-06-03 16:16:03 +02:00
Roberto Viola
8a9b5a3cc9 Peloton Rowing with Concept 2 (Issue #1481)
https://github.com/cagnulein/qdomyos-zwift/issues/1481#issuecomment-1574706758
2023-06-03 08:40:15 +02:00
Roberto Viola
46792b3c4f build 574 2023-06-03 07:20:37 +02:00
Roberto Viola
5662f90e31 2.13.66 2023-06-03 07:18:22 +02:00
Roberto Viola
81c94738b0 Use Peloton workout name in fit file #1502 2023-06-03 07:15:52 +02:00
Roberto Viola
b3874957ca Pro-form Sport RL rower Bluetooth Name I_RW Pace and Speed are incorrect #1498 2023-06-03 06:56:44 +02:00
Roberto Viola
7f16b04824 Peloton Rowing with Concept 2 (Issue #1481)
https://github.com/cagnulein/qdomyos-zwift/issues/1481#issuecomment-1574648781
2023-06-03 06:44:43 +02:00
Roberto Viola
a3af5be2ce Peloton Rowing with Concept 2 (Issue #1481)
https://github.com/cagnulein/qdomyos-zwift/issues/1481#issuecomment-1574354738
2023-06-03 06:00:05 +02:00
Roberto Viola
033ab6bd16 Echelon Row Sport Pace & Odometer Data Wrong #1500 2023-06-03 05:50:10 +02:00
Roberto Viola
38df1caf10 build 573 2023-06-02 17:58:51 +02:00
Roberto Viola
ef909a35df negative HR (Issue #1501) 2023-06-02 17:48:48 +02:00
Roberto Viola
65777dea2d Echelon Row Sport Pace & Odometer Data Wrong #1500 2023-06-02 17:46:11 +02:00
Roberto Viola
f2554ad454 Echelon Row Sport Pace & Odometer Data Wrong (Issue #1500) 2023-06-02 16:00:10 +02:00
Roberto Viola
56c04335ae Add FTMS device rower setting #1497 2023-06-02 12:13:42 +02:00
Roberto Viola
c5cf31b228 Peloton Rowing with Concept 2 (Issue #1481) 2023-06-02 07:26:14 +02:00
Roberto Viola
1b04588b4e Peloton Rowing with Concept 2 (Issue #1481) 2023-06-02 07:19:17 +02:00
Roberto Viola
c99c008b64 Peloton Rowing with Concept 2 (Issue #1481) 2023-06-02 07:16:33 +02:00
Roberto Viola
af2db915b4 Vision 600E Treadmill FTMS #1499 2023-06-02 07:06:10 +02:00
Roberto Viola
1c2a220ae4 SmartRow rower on iOS #1485 2023-06-02 07:01:37 +02:00
David Mason
77cb8439c0 Override keyword 1472 (#1475)
* #1472 make a lack of override keyword a compile error

* #1472 added override keyword as recommended by QtCreator

* #1472 deleting void Virtual* in prep for merge from master

* fix typo in the merge

---------

Co-authored-by: Roberto Viola <cagnulein@gmail.com>
2023-06-01 16:46:14 +02:00
Roberto Viola
5f14e7aa22 SmartRow rower on iOS #1485 2023-06-01 16:32:16 +02:00
Roberto Viola
e0ab1edbb6 Peloton Rowing with Concept 2 (Issue #1481) 2023-06-01 15:23:46 +02:00
Roberto Viola
ff09896cf4 Octane Fitness Q37xi Support #1023 2023-06-01 15:02:47 +02:00
Roberto Viola
a9a118d03a 2.13.64 2023-06-01 09:07:02 +02:00
Roberto Viola
f3d6f13be9 Rower AVG pace #1158 2023-06-01 09:04:44 +02:00
Roberto Viola
f23ec88dfb Peloton Rowing with Concept 2 (Issue #1481)
colors!
2023-06-01 08:52:28 +02:00
Roberto Viola
9027eb961f Peloton Rowing with Concept 2 (Issue #1481) 2023-06-01 08:34:10 +02:00
Roberto Viola
6b637e1d92 Peloton Rowing with Concept 2 #1481 2023-05-31 17:55:20 +02:00
Roberto Viola
e96eceb271 Peloton Rowing with Concept 2 #1481 2023-05-31 09:56:00 +02:00
Roberto Viola
a77074a874 Rowing Concept2 Pm3, Pm4 (Bluetooth) #1486 2023-05-31 09:46:44 +02:00
Roberto Viola
1927ad9577 CSafe Rower (#1491)
* very basic csafe implementation

* trying to fix build

* fixing build

* Update csaferower.cpp

* Update csafe.h

* Update csafe.h

* Update csafe.cpp

* Revert "Update csafe.h"

This reverts commit 3af958da71.

* builds

* ready to merge!
2023-05-30 19:14:07 +02:00
Roberto Viola
f79fd80838 Peloton Rowing with Concept 2 #1481
target pace tile added
2023-05-30 11:46:07 +02:00
Roberto Viola
cfe05c76f4 BH NLS12 ELLIPTICAL #1393 2023-05-30 09:10:05 +02:00
Roberto Viola
4c8da03f19 Peloton Rowing with Concept 2 #1481 2023-05-30 08:45:13 +02:00
Roberto Viola
7abf133a61 Merge branch 'master' of https://github.com/cagnulein/qdomyos-zwift 2023-05-29 08:29:09 +02:00
Roberto Viola
383ecc6381 version 2.13.59 2023-05-29 08:27:09 +02:00
Roberto Viola
dfd68c4445 Peloton Rower Pace (#1490)
* Update peloton.cpp

* added setting for the level and parsed

* handle target speed on trainprogram.cpp

* changespeed signal handled on the training program
2023-05-29 08:24:20 +02:00
Roberto Viola
cd689cb6fc Linux WebSockects in CI (#1489)
* Update main.yml

* Update main.yml
2023-05-28 19:21:49 +02:00
Roberto Viola
43094f41e2 Update ftmsrowertestdata.h 2023-05-28 06:40:51 +02:00
Roberto Viola
ad6d683b09 Concept 2 Rower #335 2023-05-28 06:08:58 +02:00
Roberto Viola
db5d177925 Concept 2 Rower #335 2023-05-27 21:12:16 +02:00
Roberto Viola
bfe6838acc replacing / with - in the xml training program file name 2023-05-27 18:45:25 +02:00
Roberto Viola
4a061acbfb peloton training program xml in the training folder with also the air date 2023-05-27 18:21:46 +02:00
Roberto Viola
5326089804 pm5 rower fix 2023-05-27 18:06:10 +02:00
Roberto Viola
42c6e35219 SmartRow rower on iOS #1485 2023-05-27 11:12:43 +02:00
Roberto Viola
a9f86f78b4 BH NLS12 ELLIPTICAL #1393 2023-05-27 08:27:19 +02:00
Roberto Viola
3ce7828c8f version 2.13.58 2023-05-27 08:00:05 +02:00
Roberto Viola
cb821f65b8 smartrow fix 2023-05-26 21:27:13 +02:00
Roberto Viola
cbc09609a0 adding request cadence to the rower charts 2023-05-26 08:00:58 +02:00
Roberto Viola
0f8ad887dd adding a separator for the auto saved training program 2023-05-25 16:44:57 +02:00
Roberto Viola
5d7f688321 version 2.13.57 2023-05-25 08:44:54 +02:00
Roberto Viola
b904af9335 Peloton Rowing with Concept 2 (Issue #1481) 2023-05-25 08:36:36 +02:00
Roberto Viola
030689217c save and send peloton xml training program by email 2023-05-25 08:36:11 +02:00
Roberto Viola
8f02feb172 bkoolbike added to ios 2023-05-25 08:13:16 +02:00
Roberto Viola
27ee8d99d8 Kickr Snap #585 2023-05-24 22:13:55 +02:00
Roberto Viola
4fcb13b11b fixing build error 2023-05-24 22:08:56 +02:00
Roberto Viola
13d488025f Bkool trainer #1483 2023-05-24 21:57:11 +02:00
Roberto Viola
c379985c68 Bkool trainer #1483 2023-05-24 10:08:34 +02:00
Roberto Viola
50e4ff371f Back to Back workouts without Restarting app cause NEGATIVE Calories #1480 2023-05-24 08:53:01 +02:00
Roberto Viola
01749bad6e Nautilus U618 [BUG] #1477 2023-05-24 08:24:47 +02:00
Roberto Viola
7ba1986929 BH Spada 2 bike (i.concept module) #486 2023-05-23 11:04:21 +02:00
David Mason
0a52f15406 Virtual device encapsulation #994 (#995)
* #887 converted a group of many fields of different subclasses of bluetoothdevice to use a single bluetoothdevice instance.
- This changes the behaviour. Previously multiple devices could be found and references stored, and the first in the order of ifs in device() used. Now the last one found is used and the others found are overwritten. This needs to be addressed.
- Still not making use of virtual destructors.

* #887 added virtualdevice abstract class and used it throughout

* #887 added the ability to hide the virtual device and still manage its deletion from the bluetoothdevice destructor, and used for the various cases where only 1 of multiple possible virtual devices are exposed via VirtualDevice().

* #887 fixes from merge

* #887 removed superfluous command

* #887 restored code deleted in merge

* typo fixed!

* Video again, just to show and see #838

* Video again, just to show and see #838

* Video again, just to show and see #838

* Video again, just to show and see (Issue #838)

* qz immediately crashes (Issue #929)

* faketreadmill HR fixed

* #927 route starting and stopping of bluetooth discovery through new functions startDiscovery() and stopDiscovery()

* #927 log a qDebug when stopDiscovery is called when the discovery agent is null

* #887 fixed merge conflict

* #997 fix merge conflict

* #997 fix merge conflict

* #887 fix merge problem

* #994 restored bluetooth class from master, and removed the deletion of the virtual devices

* #994 restored keepawakehelper.h includes for Android builds, but inside #ifdefs to avoid the little yellow "correction" flag (i.e. to remove it) from QtCreator.

* #994 restored unnecessarily adjusted white space

* #994 adjustments based on self review in the PR

* #994 adjusted header includes - put keepawakehelper in Android-only builds, and lockscreen.h in iOS only builds

* #994 removed some #includes repeated from the header

* #994 updated new device class to use inherited virtual device functionality

* #994 log deletion to qDebug

* #994 log deletion to qDebug

* #994 align qmdnsengine with master

* #994 fixed typo

* #994 fixed build errors

* #994 fix merge error

* #994 introduce VIRTUAL_DEVICE_MODE enum to say something about why the virtual device is exposed or not

* #994 updated some devices to use inherited virtual device management

* #994 reduction of diff with master

* #994 fixed typo in doc

* #994 reduction of diff with master

* #994 fix check for virtual device

* #994 reduction of diff with master

* #994 reduction of diff with master

* #994 reduction of diff with master

* #994 reduction of diff with master

* #994 reduction of diff with master

* #994 reduction of diff with master

* #994 reduction of diff with master

* #994 reduction of diff with master

* #994 reduction of diff with master

* #994 reduction of diff with master

* #994 reduction of diff with master

* #994 align submodule with master

* fixing build error

Signed-off-by: Roberto Viola <Cagnulein@gmail.com>

* #994 removed override keyword not required for this PR

* #994 removed deprecated comment

* fixing build on iOS

* from bluetoothdevice::VirtualDevice() always returning a virtualDevice pointer

Signed-off-by: Roberto Viola <Cagnulein@gmail.com>

* #994 updated some @brief comments to account for bluetoothdevice::VirtualDevice() now returning the virtual device regardless of virtual device mode.

* reverting merge error in proformrower.cpp

Signed-off-by: Roberto Viola <Cagnulein@gmail.com>

---------

Signed-off-by: Roberto Viola <Cagnulein@gmail.com>
Co-authored-by: Roberto Viola <Cagnulein@gmail.com>
2023-05-22 17:40:21 +02:00
Roberto Viola
abd2e76f4f WalkingPad X21 new version #1473 2023-05-22 14:06:23 +02:00
Roberto Viola
035d150c6d Update horizontreadmill.cpp 2023-05-21 13:26:21 +02:00
Roberto Viola
a29619feca fixing CI auth (#1474)
* Update main.yml

* Create http_parser.h

* Add files via upload

* Update main.yml
2023-05-21 11:27:22 +02:00
Roberto Viola
964be4b5d1 KETTLER TM support #1465 2023-05-21 07:18:37 +02:00
Roberto Viola
d01be6384d KETTLER TM support #1465 2023-05-20 19:00:35 +02:00
Roberto Viola
0845406940 Open WalkingPad X21 new version #1473 2023-05-20 15:54:06 +02:00
Roberto Viola
fd30c61124 KETTLER TM support #1465 2023-05-20 15:20:30 +02:00
Roberto Viola
a49b9b07ef new KinfSmith R2 treadmill ( KS-NACH-X21C ) 2023-05-20 15:10:36 +02:00
Roberto Viola
af91761a23 KETTLER TM support (#1470) 2023-05-20 12:07:16 +02:00
Roberto Viola
32af96b05b Zero ZT-2500 treadmill #1471 2023-05-20 07:29:29 +02:00
Roberto Viola
658006a12a Assault Air Runner Treadmill #1446 2023-05-19 19:36:26 +02:00
Roberto Viola
4451680cea fixing test cases for Sole treadmills 2023-05-19 12:07:50 +02:00
Roberto Viola
beaab12894 fixing floating issue with the null values 2023-05-18 17:25:26 +02:00
Roberto Viola
cc74ef6fe4 fixing overflow on kettler treadmill #1465 2023-05-18 16:06:37 +02:00
Roberto Viola
958487b0e5 Sole F85 help #1468 2023-05-18 15:33:10 +02:00
Roberto Viola
68d191d581 Open Floating on a Browser button added 2023-05-18 14:37:32 +02:00
Roberto Viola
aca68b2a10 KETTLER TM support (#1470)
* preparing the modification

* Update horizontreadmill.cpp
2023-05-18 14:06:16 +02:00
Roberto Viola
c3f013a69a add/allow minimum resistance for classic peloton workouts #1469 2023-05-17 10:00:52 +02:00
Roberto Viola
c2dc509c97 KETTLER TM support #1465 2023-05-17 09:47:08 +02:00
Roberto Viola
520726f989 Support for Ultrasport F-Bike 400B #690 2023-05-16 22:03:04 +02:00
Roberto Viola
04c7837e35 Kickr Snap #585 2023-05-16 16:07:58 +02:00
Roberto Viola
e1b097837b Proform 8 speed and inclination force #1454 2023-05-15 09:03:20 +02:00
Roberto Viola
b443b03d49 Tacx Flow requests #1460 2023-05-14 09:15:00 +02:00
Roberto Viola
c8cf9367db Auto Sync Not Working On Google TV with IPAD ios #1441 2023-05-13 14:52:21 +02:00
Roberto Viola
1a7c0be896 Reduce Incline not working on Horizon 7.0AT (01) #1458 2023-05-12 15:10:12 +02:00
Roberto Viola
bb219fdf9a fix build 2023-05-12 06:27:32 +02:00
Roberto Viola
d446186082 Reduce Incline not working on Horizon 7.0AT (01) #1458 2023-05-12 06:26:03 +02:00
Roberto Viola
1bc00b4f9d background and shadow color customization
Top bar custom color modification
#1420
2023-05-10 13:47:02 +02:00
Roberto Viola
28db6a7f70 Option for voice announcement of treadmill speed changes #1453 2023-05-09 10:06:50 +02:00
Roberto Viola
a1ad083422 Horizon Paragon X #637 2023-05-09 09:25:25 +02:00
Roberto Viola
0132a3f38d BH NLS12 ELLIPTICAL #1393 2023-05-08 14:36:09 +02:00
Roberto Viola
1a6a06ead4 version 2.13.41 2023-05-07 20:11:15 +02:00
Roberto Viola
f34f373687 BH Spada 2 bike (i.concept module) #486 2023-05-05 11:05:37 +02:00
Roberto Viola
95327f6c1a Update domyoselliptical.cpp (#1444) 2023-05-03 21:38:54 +02:00
Roberto Viola
93e60262d6 Assault Air Runner Treadmill #1446 2023-05-02 17:17:32 +02:00
Roberto Viola
992ae1c88c arranging metrics in floating window - Android qz #1131 2023-05-02 16:59:13 +02:00
Roberto Viola
5754e800d2 Xiaomi Walkingpad R2 Pro #1447 2023-04-30 20:07:30 +02:00
Roberto Viola
ee9491d5f6 Assault Air Runner Treadmill #1446 2023-04-30 19:56:52 +02:00
Roberto Viola
789c911966 Yesoul S3 FTMS #1445 2023-04-30 19:16:30 +02:00
Roberto Viola
d95c6f86c7 arranging metrics in floating window - Android qz (Issue #1131) 2023-04-28 13:44:23 +02:00
Roberto Viola
4d7da98c7a Merge branch 'master' of https://github.com/cagnulein/qdomyos-zwift 2023-04-28 13:10:20 +02:00
Roberto Viola
193518c1c1 2.13.38 543 2023-04-28 13:10:17 +02:00
Roberto Viola
32aafc3d00 Connect with strava button (#1439)
* peloton bike communicate with QZ AI Companion

* image added

* Update main.qml
2023-04-28 09:52:43 +02:00
Roberto Viola
1ffd44ae91 peloton bike communicate with QZ AI Companion 2023-04-28 09:00:34 +02:00
Roberto Viola
d3c8441717 BH Spada 2 bike (i.concept module) #486 2023-04-27 16:53:37 +02:00
Roberto Viola
ca8638abe0 UI theme (#1435)
* UI theme first commit

* status bar default color is not working yet

* all the new 3 settings are working!

---------

Co-authored-by: Roberto Viola <roberto.viola@systemceramics.com>
2023-04-27 12:20:51 +02:00
Roberto Viola
514ac12484 Horizon Paragon X #637 2023-04-27 09:27:10 +02:00
Roberto Viola
db5c4cc73e Disabling auto resistance does not work #1430 2023-04-26 14:29:29 +02:00
Roberto Viola
58f2934bb8 BH NLS12 Elliptical (#1408) 2023-04-26 14:25:48 +02:00
Roberto Viola
6c677a3a2b 2.13.37 build 542 2023-04-26 11:54:58 +02:00
Roberto Viola
2b4d04acc0 BH NLS12 Elliptical (#1408) #486 2023-04-26 11:54:08 +02:00
Roberto Viola
3841918383 Revert "BH Spada 2 bike (i.concept module) #486"
This reverts commit 95cb85fd88.
2023-04-26 11:51:13 +02:00
Roberto Viola
d843d09829 Nexgim QB-C01 smart bike #1433 2023-04-24 17:57:56 +02:00
Roberto Viola
c1bceca06f Disabling auto resistance does not work #1430 2023-04-24 15:23:39 +02:00
Roberto Viola
ec7782b86f Ypoo elliptical trainer U3 cross trainer #1412 (PR #1417) 2023-04-24 15:19:44 +02:00
Roberto Viola
ae6505bdb4 android version 2.13.35 2023-04-21 20:51:38 +02:00
Roberto Viola
3690120207 Sportplus SP-HT-1200 B IE #1429 2023-04-21 20:18:33 +02:00
Roberto Viola
dfe8c59a91 Update ftmsbiketestdata.h 2023-04-21 14:15:38 +02:00
Roberto Viola
e25abb0317 Update ftmsbiketestdata.h 2023-04-21 12:34:16 +02:00
Roberto Viola
4dd02ad1b6 Update ftmsbiketestdata.h 2023-04-21 12:04:46 +02:00
Roberto Viola
ef715f002b ios build 539 2023-04-21 11:32:17 +02:00
Roberto Viola
f02c2d4293 Diamondback 1260Sc Bike #1428 2023-04-21 11:29:07 +02:00
Roberto Viola
9a4baffe81 Stroke Rate with WaterRower COM Module doesn't decrease when I stop rowing. #1424 2023-04-21 10:18:16 +02:00
Roberto Viola
dd7e1b3861 android version 2.13.34 2023-04-20 15:21:50 +02:00
Roberto Viola
7cffb2c51e Ypoo elliptical trainer U3 cross trainer #1412 (#1417)
* init and write resistance done

* cross trainer data used, need to check with these frames

Value: 9e0000000040021800000000100014006e00

Value: 002f00000000000b000000000000000f00

* i guess I finished

* Update devices.h

* Update ypooellipticaltestdata.h
2023-04-20 14:47:01 +02:00
Roberto Viola
d6e5accc84 fixed popup on floating window 2023-04-19 16:46:20 +02:00
Roberto Viola
900a7f2d94 Conversion gain setting and conversion offset setting do not work with Tacx Neo 2 and Peloton. #1418 2023-04-19 10:47:56 +02:00
Roberto Viola
dd6e0068ee Qthttpserver for windows #1308 (#1309) 2023-04-18 21:13:07 +02:00
Roberto Viola
fd9c3f414b closing the popup on the floating if the user press the popup on the main screen 2023-04-18 17:35:10 +02:00
Roberto Viola
dd692b5b04 Peloton workout doesn't follow #1419 2023-04-18 08:54:34 +02:00
Roberto Viola
1f83bc94f2 closing the popup on the floating if the user press the popup on the main screen 2023-04-18 07:15:53 +02:00
Roberto Viola
c7386511ea bodytone zro-t4 treadmill #1416 2023-04-17 17:37:36 +02:00
Bepo7012
446c6ee027 Inclination improvement for Videos (#1415)
* Test Videos with higher fps Rates

* Set the speed limit higher, no longer a Problem

* iOS project updated

* Inclination Filter and Pause Video implemented

* Update qmdnsengine

* Revert "Update qmdnsengine"

This reverts commit 779bc6e4d0.

* Changes requested

* Fixed power selection for fakebike

* fakebike reverted, fixed bug in trainprogram speed limit

* Revert "Update qmdnsengine"

This reverts commit 779bc6e4d0.

* Video rec. factor included in max. Replay Rate

---------

Co-authored-by: Roberto Viola <cagnulein@gmail.com>
2023-04-17 17:15:17 +02:00
Roberto Viola
e85a6bc090 bodytone zro-t4 treadmill #1416 2023-04-17 17:10:25 +02:00
Roberto Viola
2a84b6075e bodytone zro-t4 treadmill #1416 2023-04-17 16:01:45 +02:00
Roberto Viola
1ff6295aae Inclination improvement for Videos (PR #1415) 2023-04-16 16:01:58 +02:00
Roberto Viola
70913cd7af label for the garmin companion in the settings 2023-04-14 08:33:20 +02:00
Roberto Viola
3576eff46e build 536 2023-04-13 19:49:17 +02:00
Roberto Viola
49984654ea peloton floating url available always even if the train program is not ready 2023-04-13 19:41:55 +02:00
Roberto Viola
c7f17cd749 BH NLS12 Elliptical (#1408)
* init done

* first phase

* test cases added

* fixing linker error

* Update iconceptellipticaltestdata.h

* test updated
2023-04-13 11:51:27 +02:00
Roberto Viola
20af8dcfed Wahoo Kickr Headwind #1281 2023-04-13 08:55:19 +02:00
Roberto Viola
1f113b0164 ios build CI (#1394) 2023-04-12 22:36:42 +02:00
Roberto Viola
11d0a33374 Kickr Snap #585 2023-04-12 11:31:07 +02:00
Roberto Viola
e371d13f0f trying to fix cadence (#1406) 2023-04-11 11:39:27 +02:00
Roberto Viola
f5d201aed1 floating window on ios works to qz ai companion app 2023-04-10 18:16:51 +02:00
Roberto Viola
d561dfa318 adding new case for the peloton ocr and toast messages 2023-04-10 11:35:27 +02:00
Roberto Viola
ef095dc9f1 ZWO Running distance file #1403 2023-04-09 08:46:17 +02:00
Roberto Viola
0db053b60a garmin running cadence fixed 2023-04-07 15:19:11 +02:00
Roberto Viola
2eeba4f9a6 adding cadenceFromAppleWatch to echelonstride 2023-04-07 13:42:58 +02:00
Roberto Viola
f4ccbfb33f QZ Peloton Auto Sync through an external device (#1400)
* it works, most of

* floating url added

* settings added!

* Update qmdnsengine

* preparing for release

* keeping the same logic between android ocr and companion ocr
2023-04-07 13:32:10 +02:00
Roberto Viola
32b9c2810f Update treadmill.cpp 2023-04-06 21:55:26 +02:00
Roberto Viola
7abc3834aa fixing android build 2023-04-06 21:53:56 +02:00
Roberto Viola
51cf710b08 foot cadence from Garmin Companion 2023-04-06 21:42:52 +02:00
Roberto Viola
34ae065c2c compatibilty with Garmin Companion 1.1.0 2023-04-06 11:24:51 +02:00
Roberto Viola
cbf0b178d6 Zwift OCR for Auto incline on freerun (PR #1369) 2023-04-06 10:01:57 +02:00
Roberto Viola
229b6a8e30 ios build fixed 2023-04-05 13:23:51 +02:00
Roberto Viola
02cc189d72 version 2.13.26 2023-04-05 08:44:42 +02:00
Roberto Viola
af9d1d97a8 Nautilus B616 connects but shows 0 for all stats #1383 2023-04-05 08:43:29 +02:00
Roberto Viola
20b3263a5b Garmin ConnectIQ Companion App (#1330)
* library added to the iOS project

* iOS build on CI

* adding app_delegate

* fixing typo

* Update main.yml

* Update main.yml

* fixing build error

* app on ios builds!

* handleURL works!

* connect to device but doesn't receive msgs

* android sdk works!

* HR receveid!

* getHR added to android

* should be everything for android

* fixing ios build

* fixing new xcode errors

* hr read from ios too!

* ios startup cleaned

* full chain on ios works!

* removing ant heart and apple watch hr from device files

* update_hr_from_external added

* fixing hr for 2 devices

* garmin hr fixed on android

* removing the ios CI

* Update fakebike.cpp

* Update lockscreen.h

* Update proformwifibike.cpp
2023-04-05 08:20:06 +02:00
Roberto Viola
f712b7bb92 Provide Increment/Decrement preferences for Speed/Incline #618 2023-04-03 19:04:28 +02:00
Roberto Viola
38b69c20e1 proformwifibike: turned on inclinationAvailableByHardware 2023-04-03 14:36:25 +02:00
Roberto Viola
5f99c1dd22 Heart Rate Monitor (Wahoo tick) going On and Off intermittently, only when in Domyos Elliptical bike setup. #1392 2023-04-03 09:49:08 +02:00
David Mason
a715849756 #1221 added test that bluetooth class performs action to activate template managers after detecting a device (#1223)
* #1221 decoupled template managers from class bluetooth and added tests

* #1221 renamed function

* #1221 updated comments

* #1221 adjusted for enhanced messages of #1287

* #1221 fixed merge error

* #1221 fix build error post-merge

* fix ios build

---------

Co-authored-by: Roberto Viola <cagnulein@gmail.com>
2023-04-03 09:33:35 +02:00
Roberto Viola
16b62d8752 Allow the resitance knob on echelon bikes to be used to switch gears (Issue #1299) 2023-04-03 09:28:58 +02:00
Roberto Viola
b68c166b01 disabled auto start of the tap for activiotreadmill.cpp 2023-04-02 18:39:50 +02:00
Roberto Viola
c6aaaa6944 android version 2.13.25 2023-04-02 05:19:30 +02:00
Roberto Viola
625e8c91eb Merge branch 'master' of https://github.com/cagnulein/qdomyos-zwift 2023-04-01 17:53:02 +02:00
Roberto Viola
4d81a51442 adding external power sensor on proformwifibikes 2023-04-01 17:52:55 +02:00
Roberto Viola
bbe3b4e369 ios android fixed 2023-04-01 12:20:55 +02:00
Roberto Viola
e94e030a00 adding toast from C++ 2023-04-01 09:30:23 +02:00
Roberto Viola
c9f8076a5e Nautilus B616 connects but shows 0 for all stats #1383 2023-04-01 08:53:37 +02:00
Roberto Viola
dbc1e43c2b iOS build fixed 2023-04-01 08:43:04 +02:00
Roberto Viola
b4ea2cd1c5 Zwift OCR for Auto incline on freerun #1369 2023-03-31 16:20:31 +02:00
Roberto Viola
e2d0c9284a Back character missing from title bar #1163 2023-03-31 14:16:01 +02:00
Roberto Viola
66bedca4a4 double back to close android app, ask before closing #1386 2023-03-31 12:20:35 +02:00
Roberto Viola
5a10627594 Confirmation on OK on the settings page #417 2023-03-31 11:52:55 +02:00
Roberto Viola
7465f71c74 Toast manager added
thanks to https://gist.github.com/jonmcclung/bae669101d17b103e94790341301c129
2023-03-31 10:50:54 +02:00
Roberto Viola
8c58f03d82 version 2.13.23 2023-03-31 10:09:02 +02:00
Roberto Viola
e199ea3fc6 Settings / auto restart #1114 2023-03-31 10:06:57 +02:00
Roberto Viola
bbd37dc36c Zwift OCR for Auto incline on freerun #1369 2023-03-30 17:30:15 +02:00
Roberto Viola
48646ec3bb Bowflex T128 #1385 2023-03-30 10:45:24 +02:00
Roberto Viola
dca0b1b917 iOS version 2.13.22 2023-03-30 07:08:57 +02:00
Roberto Viola
db78365ffd Nautilus B616 connects but shows 0 for all stats #1383 2023-03-30 06:54:01 +02:00
Roberto Viola
1325b1cd29 Add support for hometrainer Skandika X-2000 #1364 2023-03-29 16:32:37 +02:00
410 changed files with 19448 additions and 4218 deletions

View File

@@ -4,6 +4,7 @@ name: CI
env:
DISPLAY: ':99'
ACTIONS_ALLOW_UNSECURE_COMMANDS: 'true'
# Controls when the action will run. Triggers the workflow on push or pull request
# events but only for the master branch
@@ -20,6 +21,11 @@ on:
jobs:
window-build:
runs-on: windows-latest
strategy:
matrix:
config:
- {python: true}
- {python: false}
steps:
- uses: actions/checkout@v2
@@ -36,7 +42,7 @@ jobs:
with:
repository: cagnulein/qmdnsengine
path: "src/qmdnsengine/"
ref: "zwift"
ref: "zwift"
- uses: actions/checkout@v2
- name: Checkout submodule repo
@@ -54,9 +60,30 @@ jobs:
path: "src/MSIX-Toolkit/"
ref: b82af826d29e93e4c85d34fad8a405b6c49905e7
- 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.10.11
- name: download python and paddleocr
run: |
python -VV
python -m pip install opencv-python
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
with:
install: mingw-w64-x86_64-toolchain
install: mingw-w64-x86_64-toolchain mingw-w64-x86_64-qt5-webview
msystem: mingw64
release: false
@@ -66,7 +93,7 @@ jobs:
cmake-version: '3.20.x'
- name: Install Qt
uses: jurplel/install-qt-action@v2
uses: jurplel/install-qt-action@v3
with:
version: '5.15.2'
host: 'windows'
@@ -75,6 +102,20 @@ jobs:
arch: win64_mingw81
dir: "${{github.workspace}}/qt/"
install-deps: "true"
cache: 'true'
cache-key-prefix: 'install-qt-action-windows'
- 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: Build
run: |
@@ -92,22 +133,65 @@ jobs:
cp qdomyos-zwift.exe output/
cd output
windeployqt --qmldir ../../ qdomyos-zwift.exe
cp "${{github.workspace}}/qt/Qt/5.15.2/mingw81_64/bin/libwinpthread-1.dll" .
cp "${{github.workspace}}/qt/Qt/5.15.2/mingw81_64/bin/libgcc_s_seh-1.dll" .
cp "${{github.workspace}}/qt/Qt/5.15.2/mingw81_64/bin/libstdc++-6.dll" .
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 ../../../icons/iOS/iTunesArtwork@2x.png .
cp ../../AppxManifest.xml .
cp ../../windows/*.py .
mkdir adb
mkdir python
Copy-Item -Path C:\hostedtoolcache\windows\Python\3.10.11\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
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
mkdir appx
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 ../../../icons/iOS/iTunesArtwork@2x.png .
cp ../../AppxManifest.xml .
mkdir adb
cp ../../adb/* adb/
cd ..
cd appx
#../../MSIX-Toolkit/WindowsSDK/10/10.0.20348.0/x64/makeappx.exe pack /d ../output/ /p qz
#../../MSIX-Toolkit/WindowsSDK/10/10.0.20348.0/x64/makeappx.exe pack /d ../output/ /p qz
if: matrix.config.python == false
- name: Zip artifact for deployment
run: Compress-Archive src/debug/output release.zip
- name: Archive windows binary
uses: actions/upload-artifact@v2
with:
name: windows-binary
path: src/debug/output
path: release.zip
if: matrix.config.python
- name: Archive windows binary
uses: actions/upload-artifact@v2
with:
name: windows-binary-no-python
path: release.zip
if: ${{ ! matrix.config.python }}
# window-steam-build:
# runs-on: windows-latest
@@ -237,15 +321,36 @@ jobs:
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 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
- name: Install Qt
uses: jurplel/install-qt-action@v2
uses: jurplel/install-qt-action@v3
with:
version: '5.15.2'
host: 'linux'
modules: 'qtnetworkauth qtcharts'
cache: 'true'
cache-key-prefix: 'install-qt-action-linux'
- 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: Compile Linux Desktop
run: qmake; make -j8
@@ -406,20 +511,25 @@ jobs:
# waiting github.com/jurplel/install-qt-action/issues/63
- name: Install Qt Android
uses: jurplel/install-qt-action@v2
uses: jurplel/install-qt-action@v3
with:
version: '5.15.2'
version: '5.15.0'
host: 'linux'
target: 'android'
arch: 'android'
modules: 'qtcharts qtnetworkauth'
dir: '${{ github.workspace }}/output/android/'
cache: 'true'
cache-key-prefix: 'install-qt-action-android'
- name: Install Java
uses: actions/setup-java@v3
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: Set Android NDK 21 && build
run: |
@@ -431,6 +541,12 @@ 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
cd ..
ln -sfn $ANDROID_SDK_ROOT/ndk/21.4.7075529 $ANDROID_NDK
rm -rf /usr/local/lib/android/sdk/ndk/25.1.8937393
@@ -438,3 +554,97 @@ jobs:
- 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
- uses: r0adkll/sign-android-release@v1
name: Sign app APK
# ID used to access action output
id: sign_app
with:
releaseDirectory: ${{ github.workspace }}/output/android/build/outputs/apk/debug/
signingKeyBase64: ${{ secrets.SIGNING_KEY }}
alias: ${{ secrets.ALIAS }}
keyStorePassword: ${{ secrets.KEY_STORE_PASSWORD }}
keyPassword: ${{ secrets.KEY_PASSWORD }}
env:
# override default build-tools version (29.0.3) -- optional
BUILD_TOOLS_VERSION: "30.0.2"
- uses: r0adkll/sign-android-release@v1
name: Sign app AAB
# ID used to access action output
id: sign_aab
with:
releaseDirectory: ${{ github.workspace }}/output/android/build/outputs/bundle/debug/
signingKeyBase64: ${{ secrets.SIGNING_KEY }}
alias: ${{ secrets.ALIAS }}
keyStorePassword: ${{ secrets.KEY_STORE_PASSWORD }}
keyPassword: ${{ secrets.KEY_PASSWORD }}
env:
# override default build-tools version (29.0.3) -- optional
BUILD_TOOLS_VERSION: "30.0.2"
- uses: r0adkll/upload-google-play@v1
with:
serviceAccountJsonPlainText: ${{ secrets.SERVICE_ACCOUNT_JSON }}
packageName: org.cagnulen.qdomyoszwift
releaseFiles: ${{steps.sign_aab.outputs.signedReleaseFile}}
track: internal
status: draft
inAppUpdatePriority: 2
ios-build:
# The type of runner that the job will run on
runs-on: macos-latest
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- 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"
- name: Install Qt iOS
uses: jurplel/install-qt-action@v3
with:
version: '5.15.2'
host: 'mac'
target: 'ios'
modules: 'qtcharts qtnetworkauth'
dir: '${{ github.workspace }}/output/ios/'
cache: 'true'
cache-key-prefix: 'install-qt-action-ios'
- name: fix qt
run: find ${{ github.workspace }}/output/ios/ -name 'ios.conf' -exec sed -i '' 's/ios-simulator/iphonesimulator/g' {} \;
- name: fix qt
run: find ${{ github.workspace }}/output/ios/ -name 'devices.py' -exec sed -i '' 's/\/usr\/bin\/python/\/usr\/bin\/python3/g' {} \;
- name: fix qt
run: find ./ -name 'qdomyos-zwift-lib.pro' -exec sed -i '' 's/TARGET = qdomyos-zwift/TARGET = qdomyoszwift/g' {} \;
- name: patching qt for bluetooth
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

2
.gitignore vendored
View File

@@ -25,7 +25,6 @@ src/secret.h
build-qdomyos-zwift-Android_Qt_5_15_2_Clang_Multi_Abi-Debug/*
**/node_modules/*
*.pro.user
template-examples/youtube-viewer/node_modules/*
template-examples/youtube-viewer/*.json
@@ -49,3 +48,4 @@ google_test/*
src/inner_templates/googlemaps/cesium-key.js
*.autosave
.vscode/settings.json
/tst/Devices/.vs

128
CODE_OF_CONDUCT.md Normal file
View File

@@ -0,0 +1,128 @@
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity
and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
overall community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or
advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email
address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
roberto.viola83@gmail.com.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series
of actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within
the community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
Community Impact Guidelines were inspired by [Mozilla's code of conduct
enforcement ladder](https://github.com/mozilla/diversity).
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see the FAQ at
https://www.contributor-covenant.org/faq. Translations are available at
https://www.contributor-covenant.org/translations.

437
QZ_ESP32/QZ_ESP32.ino Normal file
View File

@@ -0,0 +1,437 @@
/** NimBLE_Server Demo:
*
This is working to broadcast Power and Cadence under the Cycling Power Service Profile
Data tested against Edge and Phone
*
*/
#include <Arduino.h>
#include <NimBLEDevice.h>
short powerInstantaneous = 0;
short cadenceInstantaneous = 0;
short speedInstantaneous = 0;
float powerScale = 1.28; // incoming power is multiplied by this value for correction
short resistance = 0; //Not currently doing anything with this value after receiving it
bool notify = false;
// Define stuff for the Client that will receive data from Fitness Machine
// The remote service we wish to connect to.
static BLEUUID serviceUUID("1826"); // Fitness Machine
// The characteristic of the remote service we are interested in.
static BLEUUID charUUID("2ad2"); // Indoor Bike (Fitness Machine)
static BLEUUID HRserviceUUID("180D"); // HR Service
static BLEUUID HRcharUUID("2a37"); // HR Measuremente
static boolean doConnect = false;
static boolean connected = false;
static boolean doScan = false;
static BLERemoteCharacteristic *pRemoteCharacteristic;
static BLEAdvertisedDevice *myDevice;
/*
* Server Stuff
*/
static NimBLEServer *pServer;
/** None of these are required as they will be handled by the library with defaults. **
** Remove as you see fit for your needs */
class ServerCallbacks : public NimBLEServerCallbacks
{
void onConnect(NimBLEServer *pServer)
{
Serial.println("Client connected");
Serial.println("Multi-connect support: start advertising");
NimBLEDevice::startAdvertising();
};
/** Alternative onConnect() method to extract details of the connection.
* See: src/ble_gap.h for the details of the ble_gap_conn_desc struct.
*/
void onConnect(NimBLEServer *pServer, ble_gap_conn_desc *desc)
{
Serial.print("Client address: ");
Serial.println(NimBLEAddress(desc->peer_ota_addr).toString().c_str());
/** We can use the connection handle here to ask for different connection parameters.
* Args: connection handle, min connection interval, max connection interval
* latency, supervision timeout.
* Units; Min/Max Intervals: 1.25 millisecond increments.
* Latency: number of intervals allowed to skip.
* Timeout: 10 millisecond increments, try for 5x interval time for best results.
*/
pServer->updateConnParams(desc->conn_handle, 24, 48, 0, 60);
};
void onDisconnect(NimBLEServer *pServer)
{
Serial.println("Client disconnected - start advertising");
NimBLEDevice::startAdvertising();
};
void onMTUChange(uint16_t MTU, ble_gap_conn_desc *desc)
{
Serial.printf("MTU updated: %u for connection ID: %u\n", MTU, desc->conn_handle);
};
};
/** Handler class for characteristic actions */
class CharacteristicCallbacks : public NimBLECharacteristicCallbacks
{
void onRead(NimBLECharacteristic *pCharacteristic)
{
Serial.print(pCharacteristic->getUUID().toString().c_str());
Serial.print(": onRead(), value: ");
Serial.println(pCharacteristic->getValue().c_str());
};
void onWrite(NimBLECharacteristic *pCharacteristic)
{
Serial.print(pCharacteristic->getUUID().toString().c_str());
Serial.print(": onWrite(), value: ");
Serial.println(pCharacteristic->getValue().c_str());
};
/** Called before notification or indication is sent,
* the value can be changed here before sending if desired.
*/
void onNotify(NimBLECharacteristic *pCharacteristic)
{
Serial.println("Sending notification to clients");
};
/** The status returned in status is defined in NimBLECharacteristic.h.
* The value returned in code is the NimBLE host return code.
*/
void onStatus(NimBLECharacteristic *pCharacteristic, Status status, int code)
{
String str = ("Notification/Indication status code: ");
str += status;
str += ", return code: ";
str += code;
str += ", ";
str += NimBLEUtils::returnCodeToString(code);
Serial.println(str);
};
void onSubscribe(NimBLECharacteristic *pCharacteristic, ble_gap_conn_desc *desc, uint16_t subValue)
{
String str = "Client ID: ";
str += desc->conn_handle;
str += " Address: ";
str += std::string(NimBLEAddress(desc->peer_ota_addr)).c_str();
if (subValue == 0)
{
str += " Unsubscribed to ";
}
else if (subValue == 1)
{
str += " Subscribed to notifications for ";
}
else if (subValue == 2)
{
str += " Subscribed to indications for ";
}
else if (subValue == 3)
{
str += " Subscribed to notifications and indications for ";
}
str += std::string(pCharacteristic->getUUID()).c_str();
Serial.println(str);
};
};
/** Handler class for descriptor actions */
class DescriptorCallbacks : public NimBLEDescriptorCallbacks
{
void onWrite(NimBLEDescriptor *pDescriptor)
{
std::string dscVal((char *)pDescriptor->getValue(), pDescriptor->getLength());
Serial.print("Descriptor witten value:");
Serial.println(dscVal.c_str());
};
void onRead(NimBLEDescriptor *pDescriptor)
{
Serial.print(pDescriptor->getUUID().toString().c_str());
Serial.println(" Descriptor read");
};
};
/*
* Client Stuff
*/
// This callback is for when data is received from Server
static void notifyCallback(
BLERemoteCharacteristic *pBLERemoteCharacteristic,
uint8_t *pData,
size_t length,
bool isNotify)
{
powerInstantaneous = pData[8] | pData[9] << 8; // 2 bytes of power
cadenceInstantaneous = 60; //(pData[4] | pData[5] << 8) / 2; // 2 bytes of power in 0.5 resolution RPM, convert to RPM
resistance = pData[6]; // 1 byte of resistance
Serial.printf("Power = %d | Cadence = %d | Resistance = %d\n", powerInstantaneous, cadenceInstantaneous, resistance);
}
/** None of these are required as they will be handled by the library with defaults. **
** Remove as you see fit for your needs */
class MyClientCallback : public BLEClientCallbacks
{
void onConnect(BLEClient *pclient)
{
}
void onDisconnect(BLEClient *pclient)
{
connected = false;
Serial.println("onDisconnect");
}
};
bool connectToServer()
{
Serial.print("Forming a connection to ");
Serial.println(myDevice->getAddress().toString().c_str());
BLEClient *pClient = BLEDevice::createClient();
Serial.println(" - Created client");
pClient->setClientCallbacks(new MyClientCallback());
// Connect to the remove BLE Server.
pClient->connect(myDevice); // if you pass BLEAdvertisedDevice instead of address, it will be recognized type of peer device address (public or private)
Serial.println(" - Connected to server");
// Obtain a reference to the service we are after in the remote BLE server.
BLERemoteService *pRemoteService = pClient->getService(serviceUUID);
if (pRemoteService == nullptr)
{
Serial.print("Failed to find our service UUID: ");
Serial.println(serviceUUID.toString().c_str());
pClient->disconnect();
return false;
}
Serial.println(" - Found our service");
// Obtain a reference to the characteristic in the service of the remote BLE server.
pRemoteCharacteristic = pRemoteService->getCharacteristic(charUUID);
if (pRemoteCharacteristic == nullptr)
{
Serial.print("Failed to find our characteristic UUID: ");
Serial.println(charUUID.toString().c_str());
pClient->disconnect();
return false;
}
Serial.println(" - Found our characteristic");
// Read the value of the characteristic.
if (pRemoteCharacteristic->canRead())
{
std::string value = pRemoteCharacteristic->readValue();
Serial.print("The characteristic value was: ");
Serial.println(value.c_str());
}
if (pRemoteCharacteristic->canNotify())
pRemoteCharacteristic->registerForNotify(notifyCallback);
connected = true;
return true;
}
/**
* Scan for BLE servers and find the first one that advertises the service we are looking for.
*/
class MyAdvertisedDeviceCallbacks : public BLEAdvertisedDeviceCallbacks
{
/**
* Called for each advertising BLE server.
*/
/*** Only a reference to the advertised device is passed now
void onResult(BLEAdvertisedDevice advertisedDevice) { **/
void onResult(BLEAdvertisedDevice *advertisedDevice)
{
Serial.print("BLE Advertised Device found: ");
Serial.println(advertisedDevice->toString().c_str());
// We have found a device, let us now see if it contains the service we are looking for.
/********************************************************************************
if (advertisedDevice.haveServiceUUID() && advertisedDevice.isAdvertisingService(serviceUUID)) {
********************************************************************************/
if (advertisedDevice->haveServiceUUID() && advertisedDevice->isAdvertisingService(serviceUUID))
{
BLEDevice::getScan()->stop();
/*******************************************************************
myDevice = new BLEAdvertisedDevice(advertisedDevice);
*******************************************************************/
myDevice = advertisedDevice; /** Just save the reference now, no need to copy the object */
doConnect = true;
doScan = true;
} // Found our server
} // onResult
}; // MyAdvertisedDeviceCallbacks
//delays for X ms, should not block execution
void softDelay(unsigned long delayTime)
{
unsigned long startTime = millis();
while ((millis() - startTime) < delayTime)
{
//wait
}
}
/** Define callback instances globally to use for multiple Characteristics \ Descriptors */
// This section is for the Server that will broadcast the data as Cycling Power
static DescriptorCallbacks dscCallbacks;
static CharacteristicCallbacks chrCallbacks;
NimBLECharacteristic *CyclingPowerFeature = NULL;
NimBLECharacteristic *CyclingPowerMeasurement = NULL;
NimBLECharacteristic *CyclingPowerSensorLocation = NULL;
NimBLECharacteristic *HRMeasurement = NULL;
unsigned char bleBuffer[8];
unsigned char slBuffer[1];
unsigned char fBuffer[4];
unsigned short revolutions = 0;
unsigned short timestamp = 0;
unsigned short flags = 0x20;
byte sensorlocation = 0x0D;
long lastNotify = 0;
long lastRevolution = 0;
void setup()
{
Serial.begin(115200);
Serial.println("Starting NimBLE Server");
/** sets device name */
NimBLEDevice::init("QZESP");
/** Optional: set the transmit power, default is 3db */
NimBLEDevice::setPower(ESP_PWR_LVL_P9); /** +9db */
pServer = NimBLEDevice::createServer();
pServer->setCallbacks(new ServerCallbacks());
fBuffer[0] = 0x00;
fBuffer[1] = 0x00;
fBuffer[2] = 0x00;
fBuffer[3] = 0x08;
slBuffer[0] = sensorlocation & 0xff;
NimBLEService *pDeadService = pServer->createService("1818");
CyclingPowerFeature = pDeadService->createCharacteristic(
"2A65",
NIMBLE_PROPERTY::READ);
CyclingPowerSensorLocation = pDeadService->createCharacteristic(
"2A5D",
NIMBLE_PROPERTY::READ);
CyclingPowerMeasurement = pDeadService->createCharacteristic(
"2A63",
NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::NOTIFY);
CyclingPowerFeature->setValue(fBuffer, 4);
CyclingPowerSensorLocation->setValue(slBuffer, 1);
CyclingPowerMeasurement->setValue(slBuffer, 1);
/** Start the services when finished creating all Characteristics and Descriptors */
pDeadService->start();
#if 0
// HR service
NimBLEService *pHRService = pServer->createService("180D");
HRMeasurement = pHRService->createCharacteristic(
"2A37",
NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::NOTIFY);
HRMeasurement->setValue(fBuffer, 2);
/** Start the services when finished creating all Characteristics and Descriptors */
pHRService->start();
#endif
NimBLEAdvertising *pAdvertising = NimBLEDevice::getAdvertising();
/** Add the services to the advertisement data **/
// pAdvertising->addServiceUUID(pHRService->getUUID());
pAdvertising->addServiceUUID(pDeadService->getUUID());
pAdvertising->setScanResponse(true);
pAdvertising->start();
Serial.println("Advertising Started");
Serial.println("Starting Arduino BLE Client application...");
BLEDevice::init("");
// Retrieve a Scanner and set the callback we want to use to be informed when we
// have detected a new device. Specify that we want active scanning and start the
// scan to run for 5 seconds.
BLEScan *pBLEScan = BLEDevice::getScan();
pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
pBLEScan->setInterval(1349);
pBLEScan->setWindow(449);
pBLEScan->setActiveScan(true);
pBLEScan->start(5, false);
}
void loop()
{
// If the flag "doConnect" is true then we have scanned for and found the desired
// BLE Server with which we wish to connect. Now we connect to it. Once we are
// connected we set the connected flag to be true.
if (doConnect == true)
{
if (connectToServer())
{
Serial.println("We are now connected to the BLE Server.");
}
else
{
Serial.println("We have failed to connect to the server; there is nothing more we will do.");
}
doConnect = false;
}
// If we are connected to a peer BLE Server, update the characteristic each time we are reached
// with the current time since boot.
if (connected)
{
//Stuff to do when connected to Client
}
else if (doScan)
{
BLEDevice::getScan()->start(0); // this is just sample to start scan after disconnect, most likely there is better way to do it in arduino
}
// convert RPM to timestamp
if (cadenceInstantaneous != 0 && (millis()) >= (lastRevolution + (60000 / cadenceInstantaneous)))
{
revolutions++; // One crank revolution should have passed, add one revolution
timestamp = (unsigned short)(((millis() * 1024) / 1000) % 65536); // create timestamp and format
lastRevolution = millis();
}
if (millis() - lastNotify >= 1000) // do this every second
{
//if (pServer->getConnectedCount() > 0)
{
bleBuffer[0] = flags & 0xff;
bleBuffer[1] = (flags >> 8) & 0xff;
bleBuffer[2] = powerInstantaneous & 0xff;
bleBuffer[3] = (powerInstantaneous >> 8) & 0xff;
bleBuffer[4] = revolutions & 0xff;
bleBuffer[5] = (revolutions >> 8) & 0xff;
bleBuffer[6] = timestamp & 0xff;
bleBuffer[7] = (timestamp >> 8) & 0xff;
CyclingPowerMeasurement->setValue(bleBuffer, 8);
CyclingPowerMeasurement->notify();
/*bleBuffer[0] = 0;
bleBuffer[1] = powerInstantaneous;
HRMeasurement->setValue(bleBuffer, 2);
HRMeasurement->notify();*/
lastNotify = millis();
}
}
/*if (pServer->getConnectedCount() == 0)
{
powerInstantaneous = 0;
}*/
}

View File

@@ -3,7 +3,7 @@
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objectVersion = 52;
objects = {
/* Begin PBXAggregateTarget section */
@@ -143,6 +143,9 @@
87083D9626678EFA0072410D /* zwiftworkout.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87083D9526678EFA0072410D /* zwiftworkout.cpp */; };
87097D2F275EA9A30020EE6F /* sportsplusbike.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87097D2D275EA9A20020EE6F /* sportsplusbike.cpp */; };
87097D31275EA9AF0020EE6F /* moc_sportsplusbike.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87097D30275EA9AE0020EE6F /* moc_sportsplusbike.cpp */; };
8710706C29C48AEA0094D0F3 /* handleurl.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 8710706B29C48AEA0094D0F3 /* handleurl.cpp */; };
8710706E29C48AF30094D0F3 /* moc_handleurl.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 8710706D29C48AF30094D0F3 /* moc_handleurl.cpp */; };
8710707329C4A5E70094D0F3 /* GarminConnect.swift in Compile Sources */ = {isa = PBXBuildFile; fileRef = 8710707229C4A5E70094D0F3 /* GarminConnect.swift */; };
871189132893C930006A04D1 /* libQt5Multimedia.a in Link Binary With Libraries */ = {isa = PBXBuildFile; fileRef = 871189122893C92F006A04D1 /* libQt5Multimedia.a */; };
871189152893CB52006A04D1 /* libdeclarative_multimedia.a in Link Binary With Libraries */ = {isa = PBXBuildFile; fileRef = 871189142893CB51006A04D1 /* libdeclarative_multimedia.a */; };
871189172893CC45006A04D1 /* libQt5MultimediaQuick.a in Link Binary With Libraries */ = {isa = PBXBuildFile; fileRef = 871189162893CC44006A04D1 /* libQt5MultimediaQuick.a */; };
@@ -171,6 +174,8 @@
872A20DC28C5F5CE0037774D /* moc_faketreadmill.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 872A20DB28C5F5CE0037774D /* moc_faketreadmill.cpp */; };
872BAB4E261750EE006A59AB /* libQt5Charts.a in Link Binary With Libraries */ = {isa = PBXBuildFile; fileRef = 872BAB4D261750EE006A59AB /* libQt5Charts.a */; };
872BAB50261751FB006A59AB /* libqtchartsqml2.a in Link Binary With Libraries */ = {isa = PBXBuildFile; fileRef = 872BAB4F261751FB006A59AB /* libqtchartsqml2.a */; };
872DCC392A18D4A800EC9F68 /* virtualdevice.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 872DCC382A18D4A800EC9F68 /* virtualdevice.cpp */; };
872DCC3B2A18D4C000EC9F68 /* moc_virtualdevice.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 872DCC3A2A18D4C000EC9F68 /* moc_virtualdevice.cpp */; };
873063BE259DF20000DA0F44 /* heartratebelt.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 873063BC259DF20000DA0F44 /* heartratebelt.cpp */; };
873063C0259DF2C500DA0F44 /* moc_heartratebelt.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 873063BF259DF2C500DA0F44 /* moc_heartratebelt.cpp */; };
87310B1E266FBB59008BA0D6 /* smartrowrower.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87310B1B266FBB54008BA0D6 /* smartrowrower.cpp */; };
@@ -238,6 +243,8 @@
873CD22D27EF8E4B000131BC /* iosinapppurchaseproduct.mm in Compile Sources */ = {isa = PBXBuildFile; fileRef = 873CD22927EF8E4B000131BC /* iosinapppurchaseproduct.mm */; };
873CD22F27EF8EC1000131BC /* StoreKit.framework in Link Binary With Libraries */ = {isa = PBXBuildFile; fileRef = 873CD22E27EF8EC1000131BC /* StoreKit.framework */; };
873CD23027EF8EF5000131BC /* iosinapppurchasetransaction.mm in Compile Sources */ = {isa = PBXBuildFile; fileRef = 873CD22727EF8E4B000131BC /* iosinapppurchasetransaction.mm */; };
873D388B29B0D745006A2611 /* ConnectIQ.xcframework in Link Binary With Libraries */ = {isa = PBXBuildFile; fileRef = 873D388A29B0D744006A2611 /* ConnectIQ.xcframework */; };
873D388C29B0D745006A2611 /* ConnectIQ.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 873D388A29B0D744006A2611 /* ConnectIQ.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
873F022F274BE471002D0349 /* mcfbike.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 873F022D274BE471002D0349 /* mcfbike.cpp */; };
873F0231274BE47D002D0349 /* moc_mcfbike.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 873F0230274BE47D002D0349 /* moc_mcfbike.cpp */; };
87420DF6269D770F000C5EC6 /* libQt5WebView.a in Link Binary With Libraries */ = {isa = PBXBuildFile; fileRef = 87420DF5269D770F000C5EC6 /* libQt5WebView.a */; };
@@ -295,6 +302,8 @@
876F9B61275385D8006AE6FA /* moc_fitmetria_fanfit.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 876F9B60275385D8006AE6FA /* moc_fitmetria_fanfit.cpp */; };
8772A0E625E43ADB0080718C /* trxappgateusbbike.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 8772A0E525E43ADA0080718C /* trxappgateusbbike.cpp */; };
8772A0E825E43AE70080718C /* moc_trxappgateusbbike.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 8772A0E725E43AE70080718C /* moc_trxappgateusbbike.cpp */; };
8775008329E876F8008E48B7 /* iconceptelliptical.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 8775008129E876F7008E48B7 /* iconceptelliptical.cpp */; };
8775008529E87713008E48B7 /* moc_iconceptelliptical.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 8775008429E87712008E48B7 /* moc_iconceptelliptical.cpp */; };
877A080D2893DC4300C0F0AB /* CoreVideo.framework in Link Binary With Libraries */ = {isa = PBXBuildFile; fileRef = 879F74122893D705009A64C8 /* CoreVideo.framework */; };
877A7609269D8E9F0024DD2C /* WebKit.framework in Link Binary With Libraries */ = {isa = PBXBuildFile; fileRef = 877A7608269D8E9F0024DD2C /* WebKit.framework */; };
877FBA29276E684500F6C0C9 /* bowflextreadmill.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 877FBA27276E684400F6C0C9 /* bowflextreadmill.cpp */; };
@@ -315,6 +324,8 @@
878A331D25AB50C300BD13E1 /* moc_yesoulbike.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 878A331B25AB50C200BD13E1 /* moc_yesoulbike.cpp */; };
878C9E6928B77E7C00669129 /* nordictrackifitadbbike.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 878C9E6828B77E7B00669129 /* nordictrackifitadbbike.cpp */; };
878C9E6B28B77E9800669129 /* moc_nordictrackifitadbbike.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 878C9E6A28B77E9800669129 /* moc_nordictrackifitadbbike.cpp */; };
878D83742A1F33C600D7F004 /* bkoolbike.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 878D83732A1F33C600D7F004 /* bkoolbike.cpp */; };
878D83762A1F33D900D7F004 /* moc_bkoolbike.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 878D83752A1F33D900D7F004 /* moc_bkoolbike.cpp */; };
87900DC6268B672E000CB351 /* renphobike.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87900DC5268B672E000CB351 /* renphobike.cpp */; };
87900DC8268B673C000CB351 /* moc_renphobike.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87900DC7268B673C000CB351 /* moc_renphobike.cpp */; };
8790FDDF277B0ABA00247550 /* nautilustreadmill.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 8790FDDD277B0ABA00247550 /* nautilustreadmill.cpp */; };
@@ -325,6 +336,7 @@
87917A7728E768D200F8D9AC /* Client.swift in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87917A7228E768D200F8D9AC /* Client.swift */; };
8791A8AA25C8603F003B50B2 /* moc_inspirebike.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 8791A8A925C8603F003B50B2 /* moc_inspirebike.cpp */; };
8791A8AB25C861BD003B50B2 /* inspirebike.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 8791A8A825C8602A003B50B2 /* inspirebike.cpp */; };
87943AB429E0215D007575F2 /* localipaddress.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87943AB229E0215D007575F2 /* localipaddress.cpp */; };
87958F1927628D4500124B24 /* elitesterzosmart.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87958F1827628D4500124B24 /* elitesterzosmart.cpp */; };
87958F1B27628D5400124B24 /* moc_elitesterzosmart.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87958F1A27628D5400124B24 /* moc_elitesterzosmart.cpp */; };
8798C8872733E103003148B3 /* strydrunpowersensor.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 8798C8862733E103003148B3 /* strydrunpowersensor.cpp */; };
@@ -346,6 +358,8 @@
87A0C4BC262329A600121A76 /* cscbike.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87A0C4B9262329A600121A76 /* cscbike.cpp */; };
87A0C4BF262329B500121A76 /* moc_cscbike.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87A0C4BD262329B500121A76 /* moc_cscbike.cpp */; };
87A0C4C0262329B500121A76 /* moc_npecablebike.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87A0C4BE262329B500121A76 /* moc_npecablebike.cpp */; };
87A0D7522A3A4518005147F2 /* fakerower.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87A0D7502A3A4517005147F2 /* fakerower.cpp */; };
87A0D7542A3A4547005147F2 /* moc_fakerower.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87A0D7532A3A4547005147F2 /* moc_fakerower.cpp */; };
87A18F072660D5C1002D7C96 /* ftmsrower.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87A18F052660D5C0002D7C96 /* ftmsrower.cpp */; };
87A18F092660D5D9002D7C96 /* moc_ftmsrower.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87A18F082660D5D9002D7C96 /* moc_ftmsrower.cpp */; };
87A3BC222656429600D302E3 /* rower.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87A3BC1F2656429400D302E3 /* rower.cpp */; };
@@ -366,6 +380,8 @@
87B617F425F260150094A1CB /* moc_screencapture.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87B617F125F260150094A1CB /* moc_screencapture.cpp */; };
87BB1774269E983200F46A1C /* moc_webserverinfosender.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87BB1773269E983200F46A1C /* moc_webserverinfosender.cpp */; };
87BB1776269E987100F46A1C /* libQt5HttpServer.a in Link Binary With Libraries */ = {isa = PBXBuildFile; fileRef = 87BB1775269E987000F46A1C /* libQt5HttpServer.a */; };
87BCE6BD29F28F72001F70EB /* ypooelliptical.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87BCE6BC29F28F72001F70EB /* ypooelliptical.cpp */; };
87BCE6BF29F28F95001F70EB /* moc_ypooelliptical.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87BCE6BE29F28F94001F70EB /* moc_ypooelliptical.cpp */; };
87BE6FDC272D2A3100C35795 /* horizongr7bike.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87BE6FDA272D2A3100C35795 /* horizongr7bike.cpp */; };
87BE6FDE272D2A3E00C35795 /* moc_horizongr7bike.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87BE6FDD272D2A3E00C35795 /* moc_horizongr7bike.cpp */; };
87BF116D298E28CA00B5B6E7 /* pelotonbike.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87BF116C298E28CA00B5B6E7 /* pelotonbike.cpp */; };
@@ -413,6 +429,7 @@
87D269A325F535340076AA48 /* moc_skandikawiribike.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87D269A125F535300076AA48 /* moc_skandikawiribike.cpp */; };
87D269A425F535340076AA48 /* moc_m3ibike.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87D269A225F535300076AA48 /* moc_m3ibike.cpp */; };
87D44181269DE979003263D5 /* webserverinfosender.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87D44180269DE979003263D5 /* webserverinfosender.cpp */; };
87D4693629B64D8100C9A382 /* ios_app_delegate.mm in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87D4693529B64D8100C9A382 /* ios_app_delegate.mm */; };
87D5DC402823047D008CCDE7 /* truetreadmill.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87D5DC3E2823047D008CCDE7 /* truetreadmill.cpp */; };
87D5DC4228230496008CCDE7 /* moc_truetreadmill.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87D5DC4128230496008CCDE7 /* moc_truetreadmill.cpp */; };
87D91F9A2800B9970026D43C /* proformwifibike.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87D91F992800B9970026D43C /* proformwifibike.cpp */; };
@@ -457,6 +474,8 @@
87F02E4029178524000DB52C /* octaneelliptical.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87F02E3E29178523000DB52C /* octaneelliptical.cpp */; };
87F02E4229178545000DB52C /* moc_octaneelliptical.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87F02E4129178545000DB52C /* moc_octaneelliptical.cpp */; };
87F1179E26A5FBDE00541B3A /* libqtwebview_darwin.a in Link Binary With Libraries */ = {isa = PBXBuildFile; fileRef = 87420DF7269D7CE1000C5EC6 /* libqtwebview_darwin.a */; };
87F4FB5A29D550C00061BB4A /* schwinn170bike.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87F4FB5829D550BF0061BB4A /* schwinn170bike.cpp */; };
87F4FB5C29D550E00061BB4A /* moc_schwinn170bike.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87F4FB5B29D550DF0061BB4A /* moc_schwinn170bike.cpp */; };
87F527BE28EEB5AA00A9F8D5 /* qzsettings.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87F527BC28EEB5AA00A9F8D5 /* qzsettings.cpp */; };
87F93427278E0EC00088B596 /* domyosrower.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87F93426278E0EC00088B596 /* domyosrower.cpp */; };
87F93429278E0ECF0088B596 /* moc_domyosrower.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87F93428278E0ECF0088B596 /* moc_domyosrower.cpp */; };
@@ -586,6 +605,7 @@
dstPath = "";
dstSubfolderSpec = 10;
files = (
873D388C29B0D745006A2611 /* ConnectIQ.xcframework in Embed Frameworks */,
);
name = "Embed Frameworks";
runOnlyForDeploymentPostprocessing = 0;
@@ -822,6 +842,10 @@
87097D2D275EA9A20020EE6F /* sportsplusbike.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = sportsplusbike.cpp; path = ../src/sportsplusbike.cpp; sourceTree = "<group>"; };
87097D2E275EA9A20020EE6F /* sportsplusbike.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = sportsplusbike.h; path = ../src/sportsplusbike.h; sourceTree = "<group>"; };
87097D30275EA9AE0020EE6F /* moc_sportsplusbike.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = moc_sportsplusbike.cpp; sourceTree = "<group>"; };
8710706A29C48AE90094D0F3 /* handleurl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = handleurl.h; path = ../src/handleurl.h; sourceTree = "<group>"; };
8710706B29C48AEA0094D0F3 /* handleurl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = handleurl.cpp; path = ../src/handleurl.cpp; sourceTree = "<group>"; };
8710706D29C48AF30094D0F3 /* moc_handleurl.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = moc_handleurl.cpp; sourceTree = "<group>"; };
8710707229C4A5E70094D0F3 /* GarminConnect.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = GarminConnect.swift; path = ../src/ios/GarminConnect.swift; sourceTree = "<group>"; };
871189122893C92F006A04D1 /* libQt5Multimedia.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libQt5Multimedia.a; path = ../../Qt/5.15.2/ios/lib/libQt5Multimedia.a; sourceTree = "<group>"; };
871189142893CB51006A04D1 /* libdeclarative_multimedia.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libdeclarative_multimedia.a; path = ../../Qt/5.15.2/ios/qml/QtMultimedia/libdeclarative_multimedia.a; sourceTree = "<group>"; };
871189162893CC44006A04D1 /* libQt5MultimediaQuick.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libQt5MultimediaQuick.a; path = ../../Qt/5.15.2/ios/lib/libQt5MultimediaQuick.a; sourceTree = "<group>"; };
@@ -862,6 +886,9 @@
872A20DB28C5F5CE0037774D /* moc_faketreadmill.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = moc_faketreadmill.cpp; sourceTree = "<group>"; };
872BAB4D261750EE006A59AB /* libQt5Charts.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libQt5Charts.a; path = ../../Qt/5.15.2/ios/lib/libQt5Charts.a; sourceTree = "<group>"; };
872BAB4F261751FB006A59AB /* libqtchartsqml2.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libqtchartsqml2.a; path = ../../Qt/5.15.2/ios/qml/QtCharts/libqtchartsqml2.a; sourceTree = "<group>"; };
872DCC372A18D4A800EC9F68 /* virtualdevice.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = virtualdevice.h; path = ../src/virtualdevice.h; sourceTree = "<group>"; };
872DCC382A18D4A800EC9F68 /* virtualdevice.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = virtualdevice.cpp; path = ../src/virtualdevice.cpp; sourceTree = "<group>"; };
872DCC3A2A18D4C000EC9F68 /* moc_virtualdevice.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = moc_virtualdevice.cpp; sourceTree = "<group>"; };
873063BC259DF20000DA0F44 /* heartratebelt.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = heartratebelt.cpp; path = ../src/heartratebelt.cpp; sourceTree = "<group>"; };
873063BD259DF20000DA0F44 /* heartratebelt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = heartratebelt.h; path = ../src/heartratebelt.h; sourceTree = "<group>"; };
873063BF259DF2C500DA0F44 /* moc_heartratebelt.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = moc_heartratebelt.cpp; sourceTree = "<group>"; };
@@ -964,6 +991,7 @@
873CD22927EF8E4B000131BC /* iosinapppurchaseproduct.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = iosinapppurchaseproduct.mm; path = ../src/purchasing/ios/iosinapppurchaseproduct.mm; sourceTree = "<group>"; };
873CD22A27EF8E4B000131BC /* iosinapppurchasetransaction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = iosinapppurchasetransaction.h; path = ../src/purchasing/ios/iosinapppurchasetransaction.h; sourceTree = "<group>"; };
873CD22E27EF8EC1000131BC /* StoreKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = StoreKit.framework; path = System/Library/Frameworks/StoreKit.framework; sourceTree = SDKROOT; };
873D388A29B0D744006A2611 /* ConnectIQ.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = ConnectIQ.xcframework; path = ../src/ConnectIQ/iOS/ConnectIQ.xcframework; sourceTree = "<group>"; };
873F022D274BE471002D0349 /* mcfbike.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = mcfbike.cpp; path = ../src/mcfbike.cpp; sourceTree = "<group>"; };
873F022E274BE471002D0349 /* mcfbike.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = mcfbike.h; path = ../src/mcfbike.h; sourceTree = "<group>"; };
873F0230274BE47D002D0349 /* moc_mcfbike.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = moc_mcfbike.cpp; sourceTree = "<group>"; };
@@ -1054,6 +1082,9 @@
8772A0E425E43AD90080718C /* trxappgateusbbike.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = trxappgateusbbike.h; path = ../src/trxappgateusbbike.h; sourceTree = "<group>"; };
8772A0E525E43ADA0080718C /* trxappgateusbbike.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = trxappgateusbbike.cpp; path = ../src/trxappgateusbbike.cpp; sourceTree = "<group>"; };
8772A0E725E43AE70080718C /* moc_trxappgateusbbike.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = moc_trxappgateusbbike.cpp; sourceTree = "<group>"; };
8775008129E876F7008E48B7 /* iconceptelliptical.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = iconceptelliptical.cpp; path = ../src/iconceptelliptical.cpp; sourceTree = "<group>"; };
8775008229E876F7008E48B7 /* iconceptelliptical.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = iconceptelliptical.h; path = ../src/iconceptelliptical.h; sourceTree = "<group>"; };
8775008429E87712008E48B7 /* moc_iconceptelliptical.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = moc_iconceptelliptical.cpp; sourceTree = "<group>"; };
877A7606269D8E0F0024DD2C /* libqtwebview_darwin_debug.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libqtwebview_darwin_debug.a; path = ../../Qt/5.15.2/ios/plugins/webview/libqtwebview_darwin_debug.a; sourceTree = "<group>"; };
877A7608269D8E9F0024DD2C /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = System/Library/Frameworks/WebKit.framework; sourceTree = SDKROOT; };
877FBA27276E684400F6C0C9 /* bowflextreadmill.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = bowflextreadmill.cpp; path = ../src/bowflextreadmill.cpp; sourceTree = "<group>"; };
@@ -1084,6 +1115,9 @@
878C9E6728B77E7B00669129 /* nordictrackifitadbbike.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = nordictrackifitadbbike.h; path = ../src/nordictrackifitadbbike.h; sourceTree = "<group>"; };
878C9E6828B77E7B00669129 /* nordictrackifitadbbike.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = nordictrackifitadbbike.cpp; path = ../src/nordictrackifitadbbike.cpp; sourceTree = "<group>"; };
878C9E6A28B77E9800669129 /* moc_nordictrackifitadbbike.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = moc_nordictrackifitadbbike.cpp; sourceTree = "<group>"; };
878D83722A1F33C600D7F004 /* bkoolbike.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = bkoolbike.h; path = ../src/bkoolbike.h; sourceTree = "<group>"; };
878D83732A1F33C600D7F004 /* bkoolbike.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = bkoolbike.cpp; path = ../src/bkoolbike.cpp; sourceTree = "<group>"; };
878D83752A1F33D900D7F004 /* moc_bkoolbike.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = moc_bkoolbike.cpp; sourceTree = "<group>"; };
87900DC4268B672E000CB351 /* renphobike.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = renphobike.h; path = ../src/renphobike.h; sourceTree = "<group>"; };
87900DC5268B672E000CB351 /* renphobike.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = renphobike.cpp; path = ../src/renphobike.cpp; sourceTree = "<group>"; };
87900DC7268B673C000CB351 /* moc_renphobike.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = moc_renphobike.cpp; sourceTree = "<group>"; };
@@ -1097,6 +1131,8 @@
8791A8A725C8602A003B50B2 /* inspirebike.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = inspirebike.h; path = ../src/inspirebike.h; sourceTree = "<group>"; };
8791A8A825C8602A003B50B2 /* inspirebike.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = inspirebike.cpp; path = ../src/inspirebike.cpp; sourceTree = "<group>"; };
8791A8A925C8603F003B50B2 /* moc_inspirebike.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = moc_inspirebike.cpp; sourceTree = "<group>"; };
87943AB229E0215D007575F2 /* localipaddress.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = localipaddress.cpp; path = ../src/localipaddress.cpp; sourceTree = "<group>"; };
87943AB329E0215D007575F2 /* localipaddress.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = localipaddress.h; path = ../src/localipaddress.h; sourceTree = "<group>"; };
87958F1727628D4500124B24 /* elitesterzosmart.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = elitesterzosmart.h; path = ../src/elitesterzosmart.h; sourceTree = "<group>"; };
87958F1827628D4500124B24 /* elitesterzosmart.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = elitesterzosmart.cpp; path = ../src/elitesterzosmart.cpp; sourceTree = "<group>"; };
87958F1A27628D5400124B24 /* moc_elitesterzosmart.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = moc_elitesterzosmart.cpp; sourceTree = "<group>"; };
@@ -1126,6 +1162,9 @@
87A0C4BA262329A600121A76 /* npecablebike.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = npecablebike.h; path = ../src/npecablebike.h; sourceTree = "<group>"; };
87A0C4BD262329B500121A76 /* moc_cscbike.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = moc_cscbike.cpp; sourceTree = "<group>"; };
87A0C4BE262329B500121A76 /* moc_npecablebike.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = moc_npecablebike.cpp; sourceTree = "<group>"; };
87A0D7502A3A4517005147F2 /* fakerower.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = fakerower.cpp; path = ../src/fakerower.cpp; sourceTree = "<group>"; };
87A0D7512A3A4517005147F2 /* fakerower.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = fakerower.h; path = ../src/fakerower.h; sourceTree = "<group>"; };
87A0D7532A3A4547005147F2 /* moc_fakerower.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = moc_fakerower.cpp; sourceTree = "<group>"; };
87A18F052660D5C0002D7C96 /* ftmsrower.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ftmsrower.cpp; path = ../src/ftmsrower.cpp; sourceTree = "<group>"; };
87A18F062660D5C1002D7C96 /* ftmsrower.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ftmsrower.h; path = ../src/ftmsrower.h; sourceTree = "<group>"; };
87A18F082660D5D9002D7C96 /* moc_ftmsrower.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = moc_ftmsrower.cpp; sourceTree = "<group>"; };
@@ -1158,6 +1197,9 @@
87B617F125F260150094A1CB /* moc_screencapture.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = moc_screencapture.cpp; sourceTree = "<group>"; };
87BB1773269E983200F46A1C /* moc_webserverinfosender.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = moc_webserverinfosender.cpp; sourceTree = "<group>"; };
87BB1775269E987000F46A1C /* libQt5HttpServer.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libQt5HttpServer.a; path = ../../Qt/5.15.2/ios/lib/libQt5HttpServer.a; sourceTree = "<group>"; };
87BCE6BB29F28F72001F70EB /* ypooelliptical.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ypooelliptical.h; path = ../src/ypooelliptical.h; sourceTree = "<group>"; };
87BCE6BC29F28F72001F70EB /* ypooelliptical.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ypooelliptical.cpp; path = ../src/ypooelliptical.cpp; sourceTree = "<group>"; };
87BCE6BE29F28F94001F70EB /* moc_ypooelliptical.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = moc_ypooelliptical.cpp; sourceTree = "<group>"; };
87BE6FDA272D2A3100C35795 /* horizongr7bike.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = horizongr7bike.cpp; path = ../src/horizongr7bike.cpp; sourceTree = "<group>"; };
87BE6FDB272D2A3100C35795 /* horizongr7bike.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = horizongr7bike.h; path = ../src/horizongr7bike.h; sourceTree = "<group>"; };
87BE6FDD272D2A3E00C35795 /* moc_horizongr7bike.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = moc_horizongr7bike.cpp; sourceTree = "<group>"; };
@@ -1230,6 +1272,7 @@
87D269A125F535300076AA48 /* moc_skandikawiribike.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = moc_skandikawiribike.cpp; sourceTree = "<group>"; };
87D269A225F535300076AA48 /* moc_m3ibike.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = moc_m3ibike.cpp; sourceTree = "<group>"; };
87D44180269DE979003263D5 /* webserverinfosender.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = webserverinfosender.cpp; path = ../src/webserverinfosender.cpp; sourceTree = "<group>"; };
87D4693529B64D8100C9A382 /* ios_app_delegate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = ios_app_delegate.mm; path = ../src/ios/ios_app_delegate.mm; sourceTree = "<group>"; };
87D5DC3E2823047D008CCDE7 /* truetreadmill.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = truetreadmill.cpp; path = ../src/truetreadmill.cpp; sourceTree = "<group>"; };
87D5DC3F2823047D008CCDE7 /* truetreadmill.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = truetreadmill.h; path = ../src/truetreadmill.h; sourceTree = "<group>"; };
87D5DC4128230496008CCDE7 /* moc_truetreadmill.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = moc_truetreadmill.cpp; sourceTree = "<group>"; };
@@ -1293,6 +1336,9 @@
87F02E3E29178523000DB52C /* octaneelliptical.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = octaneelliptical.cpp; path = ../src/octaneelliptical.cpp; sourceTree = "<group>"; };
87F02E3F29178524000DB52C /* octaneelliptical.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = octaneelliptical.h; path = ../src/octaneelliptical.h; sourceTree = "<group>"; };
87F02E4129178545000DB52C /* moc_octaneelliptical.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = moc_octaneelliptical.cpp; sourceTree = "<group>"; };
87F4FB5829D550BF0061BB4A /* schwinn170bike.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = schwinn170bike.cpp; path = ../src/schwinn170bike.cpp; sourceTree = "<group>"; };
87F4FB5929D550BF0061BB4A /* schwinn170bike.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = schwinn170bike.h; path = ../src/schwinn170bike.h; sourceTree = "<group>"; };
87F4FB5B29D550DF0061BB4A /* moc_schwinn170bike.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = moc_schwinn170bike.cpp; sourceTree = "<group>"; };
87F527BC28EEB5AA00A9F8D5 /* qzsettings.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = qzsettings.cpp; path = ../src/qzsettings.cpp; sourceTree = "<group>"; };
87F527BD28EEB5AA00A9F8D5 /* qzsettings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = qzsettings.h; path = ../src/qzsettings.h; sourceTree = "<group>"; };
87F93425278E0EC00088B596 /* domyosrower.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = domyosrower.h; path = ../src/domyosrower.h; sourceTree = "<group>"; };
@@ -1602,6 +1648,7 @@
023642106C14651D2E1F4D5D /* dialogplugin in Link Binary With Libraries */,
133CA0345CD2BFB03079A655 /* qmlfolderlistmodelplugin in Link Binary With Libraries */,
4AAA7380490CBDBAA8587CFA /* qmlsettingsplugin in Link Binary With Libraries */,
873D388B29B0D745006A2611 /* ConnectIQ.xcframework in Link Binary With Libraries */,
3BD5A5F95DF5239184791B58 /* dialogsprivateplugin in Link Binary With Libraries */,
EF98F8C34BE322582E9B73D7 /* qtquickcontrolsplugin in Link Binary With Libraries */,
7C8D236C48F2964061C3457C /* widgetsplugin in Link Binary With Libraries */,
@@ -1674,6 +1721,13 @@
25B08E2869634E9BCBA333A2 /* Generated Sources */ = {
isa = PBXGroup;
children = (
87A0D7532A3A4547005147F2 /* moc_fakerower.cpp */,
878D83752A1F33D900D7F004 /* moc_bkoolbike.cpp */,
872DCC3A2A18D4C000EC9F68 /* moc_virtualdevice.cpp */,
87BCE6BE29F28F94001F70EB /* moc_ypooelliptical.cpp */,
8775008429E87712008E48B7 /* moc_iconceptelliptical.cpp */,
8710706D29C48AF30094D0F3 /* moc_handleurl.cpp */,
87F4FB5B29D550DF0061BB4A /* moc_schwinn170bike.cpp */,
87B187BC29B8C577007EEF9D /* moc_ziprotreadmill.cpp */,
87A0771129B6420200A368BF /* moc_wahookickrheadwind.cpp */,
874D272129AFA13B0007C079 /* moc_apexbike.cpp */,
@@ -1835,6 +1889,23 @@
2EB56BE3C2D93CDAB0C52E67 /* Sources */ = {
isa = PBXGroup;
children = (
87A0D7502A3A4517005147F2 /* fakerower.cpp */,
87A0D7512A3A4517005147F2 /* fakerower.h */,
878D83732A1F33C600D7F004 /* bkoolbike.cpp */,
878D83722A1F33C600D7F004 /* bkoolbike.h */,
872DCC382A18D4A800EC9F68 /* virtualdevice.cpp */,
872DCC372A18D4A800EC9F68 /* virtualdevice.h */,
87BCE6BC29F28F72001F70EB /* ypooelliptical.cpp */,
87BCE6BB29F28F72001F70EB /* ypooelliptical.h */,
8775008129E876F7008E48B7 /* iconceptelliptical.cpp */,
8775008229E876F7008E48B7 /* iconceptelliptical.h */,
87943AB229E0215D007575F2 /* localipaddress.cpp */,
87943AB329E0215D007575F2 /* localipaddress.h */,
8710706B29C48AEA0094D0F3 /* handleurl.cpp */,
8710706A29C48AE90094D0F3 /* handleurl.h */,
87D4693529B64D8100C9A382 /* ios_app_delegate.mm */,
87F4FB5829D550BF0061BB4A /* schwinn170bike.cpp */,
87F4FB5929D550BF0061BB4A /* schwinn170bike.h */,
87B187B929B8C552007EEF9D /* ziprotreadmill.cpp */,
87B187BA29B8C552007EEF9D /* ziprotreadmill.h */,
87A0770F29B641D500A368BF /* wahookickrheadwind.cpp */,
@@ -2174,6 +2245,7 @@
68418A2D51B69FC30BF5A41C /* virtualbike.h */,
35E903698E72424585D33829 /* virtualtreadmill.h */,
C8CE72E7B224D8B886614E3F /* domyosbike.h */,
8710707229C4A5E70094D0F3 /* GarminConnect.swift */,
);
name = Sources;
sourceTree = "<group>";
@@ -2266,6 +2338,7 @@
AF39DD055C3EF8226FBE929D /* Frameworks */ = {
isa = PBXGroup;
children = (
873D388A29B0D744006A2611 /* ConnectIQ.xcframework */,
879F74142893D732009A64C8 /* CoreMedia.framework */,
879F74122893D705009A64C8 /* CoreVideo.framework */,
879F74102893D5B7009A64C8 /* libqavfcamera.a */,
@@ -2876,6 +2949,7 @@
87D269A425F535340076AA48 /* moc_m3ibike.cpp in Compile Sources */,
EA780CE97E201242E33E6EEE /* bike.cpp in Compile Sources */,
8738249827E646E3004F1B46 /* dirconmanager.cpp in Compile Sources */,
87D4693629B64D8100C9A382 /* ios_app_delegate.mm in Compile Sources */,
87C5F0D926285E7E0067A1B5 /* moc_mimeattachment.cpp in Compile Sources */,
87B617F225F260150094A1CB /* moc_fitshowtreadmill.cpp in Compile Sources */,
87473A9627ECA9EE00C203F5 /* proformrower.cpp in Compile Sources */,
@@ -2930,12 +3004,14 @@
873063C0259DF2C500DA0F44 /* moc_heartratebelt.cpp in Compile Sources */,
DD5ED224478CB82859C61B9F /* fit_buffered_record_mesg_broadcaster.cpp in Compile Sources */,
87368825259C602800C71C7E /* watchAppStart.swift in Compile Sources */,
87BCE6BF29F28F95001F70EB /* moc_ypooelliptical.cpp in Compile Sources */,
876ED21925C3E9000065F3DC /* moc_ftmsbike.cpp in Compile Sources */,
87C5F0BD26285E5F0067A1B5 /* chronobike.cpp in Compile Sources */,
872A20DA28C5EC380037774D /* faketreadmill.cpp in Compile Sources */,
87900DC8268B673C000CB351 /* moc_renphobike.cpp in Compile Sources */,
87CC3B9E25A08812001EC5A8 /* moc_elliptical.cpp in Compile Sources */,
876BFC9C27BE35C5001D7645 /* proformelliptical.cpp in Compile Sources */,
878D83762A1F33D900D7F004 /* moc_bkoolbike.cpp in Compile Sources */,
E7F190E59DC975BA4CA65F0C /* fit_crc.cpp in Compile Sources */,
87A18F092660D5D9002D7C96 /* moc_ftmsrower.cpp in Compile Sources */,
DA1DC0B761BD7A3004BCF43D /* fit_date_time.cpp in Compile Sources */,
@@ -2963,8 +3039,10 @@
87646C2227B5065100F82131 /* moc_bhfitnesselliptical.cpp in Compile Sources */,
873824B127E64706004F1B46 /* moc_browser_p.cpp in Compile Sources */,
873824B627E64707004F1B46 /* moc_hostname_p.cpp in Compile Sources */,
87A0D7542A3A4547005147F2 /* moc_fakerower.cpp in Compile Sources */,
873824EA27E647A8004F1B46 /* browser.cpp in Compile Sources */,
87E34C2B2886F95400CEDE4B /* octanetreadmill.cpp in Compile Sources */,
87A0D7522A3A4518005147F2 /* fakerower.cpp in Compile Sources */,
87B187BB29B8C552007EEF9D /* ziprotreadmill.cpp in Compile Sources */,
87BF116D298E28CA00B5B6E7 /* pelotonbike.cpp in Compile Sources */,
87DAE16A26E9FF5000B0527E /* moc_kingsmithr2treadmill.cpp in Compile Sources */,
@@ -2994,6 +3072,7 @@
876ED21625C3E8DE0065F3DC /* schwinnic4bike.cpp in Compile Sources */,
879E5AAA289C05A500FEA38A /* moc_proformwifitreadmill.cpp in Compile Sources */,
87D269A325F535340076AA48 /* moc_skandikawiribike.cpp in Compile Sources */,
87F4FB5C29D550E00061BB4A /* moc_schwinn170bike.cpp in Compile Sources */,
87C5F0C226285E5F0067A1B5 /* emailaddress.cpp in Compile Sources */,
873824AF27E64706004F1B46 /* moc_characteristicwriteprocessor2ad9.cpp in Compile Sources */,
25F2400F80DAFBD41FE5CC75 /* fit_field.cpp in Compile Sources */,
@@ -3020,12 +3099,14 @@
FE77C778768741F1A161682E /* fit_mesg_definition.cpp in Compile Sources */,
875F69B926342E8D0009FD78 /* spirittreadmill.cpp in Compile Sources */,
87DF68B825E2673B00FCDA46 /* eslinkertreadmill.cpp in Compile Sources */,
87BCE6BD29F28F72001F70EB /* ypooelliptical.cpp in Compile Sources */,
87C7074327E4CF5900E79C46 /* keepbike.cpp in Compile Sources */,
878C9E6928B77E7C00669129 /* nordictrackifitadbbike.cpp in Compile Sources */,
8798C8892733E10E003148B3 /* moc_strydrunpowersensor.cpp in Compile Sources */,
8781907E2615089D0085E656 /* peloton.cpp in Compile Sources */,
2B800DC34C91D8B080DEFBE8 /* fit_mesg_with_event_broadcaster.cpp in Compile Sources */,
6DC5D7C695B8763F9E2E029F /* fit_profile.cpp in Compile Sources */,
8710706C29C48AEA0094D0F3 /* handleurl.cpp in Compile Sources */,
87C5F0B726285E5F0067A1B5 /* mimecontentformatter.cpp in Compile Sources */,
23191C28CB29474279752FD3 /* fit_protocol_validator.cpp in Compile Sources */,
275D55B5D956B2E5F1B7E46E /* fit_unicode.cpp in Compile Sources */,
@@ -3034,6 +3115,7 @@
87061399286D8D6500D2446E /* moc_wobjectdefs.cpp in Compile Sources */,
873824BA27E64707004F1B46 /* moc_server_p.cpp in Compile Sources */,
87958F1927628D4500124B24 /* elitesterzosmart.cpp in Compile Sources */,
87943AB429E0215D007575F2 /* localipaddress.cpp in Compile Sources */,
87EB917627EE5FB3002535E1 /* nautilusbike.cpp in Compile Sources */,
ACB47DC464A2BC9D39C544AD /* gpx.cpp in Compile Sources */,
6361329E515248BB41640C07 /* homeform.cpp in Compile Sources */,
@@ -3061,11 +3143,13 @@
E40895A73216AC52D35083D9 /* signalhandler.cpp in Compile Sources */,
873CD22427EF8E18000131BC /* inappproductqmltype.cpp in Compile Sources */,
87DF68BF25E2675100FCDA46 /* moc_schwinnic4bike.cpp in Compile Sources */,
8710707329C4A5E70094D0F3 /* GarminConnect.swift in Compile Sources */,
BE1D17BBF32F04829E1B3767 /* toorxtreadmill.cpp in Compile Sources */,
879A38C8281BD83300F78B2A /* characteristicnotifier2ad9.cpp in Compile Sources */,
4697729B15991E98D6A2533D /* treadmill.cpp in Compile Sources */,
87C481FC26DFA7D1006211AD /* moc_eliterizer.cpp in Compile Sources */,
20AA270C9F447F42F5DC2FF2 /* trainprogram.cpp in Compile Sources */,
8710706E29C48AF30094D0F3 /* moc_handleurl.cpp in Compile Sources */,
87F93429278E0ECF0088B596 /* moc_domyosrower.cpp in Compile Sources */,
87C5F0C026285E5F0067A1B5 /* mimepart.cpp in Compile Sources */,
47E45EE0BB22C1E4332F1D1D /* trxappgateusbtreadmill.cpp in Compile Sources */,
@@ -3083,6 +3167,7 @@
87C5F0CF26285E7E0067A1B5 /* moc_mimepart.cpp in Compile Sources */,
87EB918A27EE5FE7002535E1 /* qdomyoszwift_qmltyperegistrations.cpp in Compile Sources */,
87182A0B276BBB1200141463 /* moc_virtualrower.cpp in Compile Sources */,
872DCC3B2A18D4C000EC9F68 /* moc_virtualdevice.cpp in Compile Sources */,
0317752B0C295CAB82D37E45 /* virtualtreadmill.cpp in Compile Sources */,
8742C2B427C92C48007D3FA0 /* moc_wahookickrsnapbike.cpp in Compile Sources */,
878531692711A3EC004B153D /* moc_fakebike.cpp in Compile Sources */,
@@ -3091,12 +3176,14 @@
87097D31275EA9AF0020EE6F /* moc_sportsplusbike.cpp in Compile Sources */,
87819080261508B10085E656 /* moc_peloton.cpp in Compile Sources */,
7EC1321DD83EAAFAA2B7109C /* domyosbike.cpp in Compile Sources */,
8775008529E87713008E48B7 /* moc_iconceptelliptical.cpp in Compile Sources */,
614192CB787D12C3E98ADE55 /* lockscreen.mm in Compile Sources */,
87A0C4BB262329A600121A76 /* npecablebike.cpp in Compile Sources */,
873CD22D27EF8E4B000131BC /* iosinapppurchaseproduct.mm in Compile Sources */,
873CD20727EF8D8A000131BC /* inappproduct.cpp in Compile Sources */,
87A3BC26265642A300D302E3 /* moc_rower.cpp in Compile Sources */,
87EFE45B27A51901006EA1C3 /* moc_nautiluselliptical.cpp in Compile Sources */,
872DCC392A18D4A800EC9F68 /* virtualdevice.cpp in Compile Sources */,
0F974CB18B3E792B42270F19 /* FitDecode.mm in Compile Sources */,
87440FBF2640292900E4DC0B /* moc_fitplusbike.cpp in Compile Sources */,
87B617EC25F25FED0094A1CB /* screencapture.cpp in Compile Sources */,
@@ -3136,6 +3223,7 @@
87D2699F25F535200076AA48 /* m3ibike.cpp in Compile Sources */,
87917A7528E768D200F8D9AC /* Connection.swift in Compile Sources */,
87FFA13727BBE3FF00924E4E /* solebike.cpp in Compile Sources */,
87F4FB5A29D550C00061BB4A /* schwinn170bike.cpp in Compile Sources */,
7352E0F0EE5366AC809B9D64 /* qrc_qml.cpp in Compile Sources */,
873824E727E647A8004F1B46 /* record.cpp in Compile Sources */,
B38F3288D4AE4025465C1953 /* moc_bike.cpp in Compile Sources */,
@@ -3171,6 +3259,7 @@
E8B499F921FB0AB55C7A8A8B /* moc_gpx.cpp in Compile Sources */,
87E6A85825B5C88E00371D28 /* moc_flywheelbike.cpp in Compile Sources */,
8754D24C27F786F0003D7054 /* virtualrower.swift in Compile Sources */,
878D83742A1F33C600D7F004 /* bkoolbike.cpp in Compile Sources */,
873824B727E64707004F1B46 /* moc_characteristicwriteprocessor.cpp in Compile Sources */,
87310B1F266FBB59008BA0D6 /* homefitnessbuddy.cpp in Compile Sources */,
140BAAA8823E05940EF35A38 /* moc_treadmill.cpp in Compile Sources */,
@@ -3187,6 +3276,7 @@
87D269A025F535200076AA48 /* skandikawiribike.cpp in Compile Sources */,
8738249427E646E3004F1B46 /* characteristicnotifier2a5b.cpp in Compile Sources */,
8768D1FB285081FE00F58E3A /* nordictrackifitadbtreadmill.cpp in Compile Sources */,
8775008329E876F8008E48B7 /* iconceptelliptical.cpp in Compile Sources */,
87B187BD29B8C577007EEF9D /* moc_ziprotreadmill.cpp in Compile Sources */,
877FBA2B276E684E00F6C0C9 /* moc_bowflextreadmill.cpp in Compile Sources */,
874D272229AFA13B0007C079 /* moc_apexbike.cpp in Compile Sources */,
@@ -3572,11 +3662,11 @@
buildSettings = {
APPLICATION_EXTENSION_API_ONLY = NO;
"ARCHS[sdk=iphoneos*]" = arm64;
"ARCHS[sdk=iphonesimulator*]" = x86_64;
"ARCHS[sdk=iphonesimulator*]" = "$(ARCHS_STANDARD)";
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements";
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 514;
CURRENT_PROJECT_VERSION = 612;
DEVELOPMENT_TEAM = 6335M7T29D;
ENABLE_BITCODE = NO;
HEADER_SEARCH_PATHS = (
@@ -3740,11 +3830,11 @@
buildSettings = {
APPLICATION_EXTENSION_API_ONLY = NO;
"ARCHS[sdk=iphoneos*]" = arm64;
"ARCHS[sdk=iphonesimulator*]" = x86_64;
"ARCHS[sdk=iphonesimulator*]" = "$(ARCHS_STANDARD)";
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements";
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 514;
CURRENT_PROJECT_VERSION = 612;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = 6335M7T29D;
ENABLE_BITCODE = NO;
@@ -3948,7 +4038,7 @@
CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 514;
CURRENT_PROJECT_VERSION = 612;
DEVELOPMENT_TEAM = 6335M7T29D;
ENABLE_BITCODE = YES;
ENABLE_STRICT_OBJC_MSGSEND = YES;
@@ -3968,7 +4058,11 @@
GCC_WARN_UNUSED_VARIABLE = YES;
IBSC_MODULE = watchkit_Extension;
INFOPLIST_FILE = watchkit/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
"@loader_path/../Frameworks",
);
MARKETING_VERSION = 2.13;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
@@ -4040,7 +4134,7 @@
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 514;
CURRENT_PROJECT_VERSION = 612;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = 6335M7T29D;
ENABLE_BITCODE = YES;
@@ -4056,7 +4150,11 @@
GCC_WARN_UNUSED_VARIABLE = YES;
IBSC_MODULE = watchkit_Extension;
INFOPLIST_FILE = watchkit/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/../Frameworks",
"@loader_path/../Frameworks",
);
MARKETING_VERSION = 2.13;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
@@ -4077,8 +4175,9 @@
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = watchos;
SKIP_INSTALL = YES;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OBJC_BRIDGING_HEADER = "watchkit-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
SWIFT_OPTIMIZATION_LEVEL = "-O";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 4;
VALIDATE_PRODUCT = YES;
@@ -4127,7 +4226,7 @@
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 514;
CURRENT_PROJECT_VERSION = 612;
DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\"";
ENABLE_BITCODE = YES;
ENABLE_PREVIEWS = YES;
@@ -4167,7 +4266,11 @@
../../Qt/5.15.2/ios/include/QtMultimedia,
);
INFOPLIST_FILE = "watchkit Extension/Info.plist";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 2.13;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
@@ -4237,7 +4340,7 @@
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 514;
CURRENT_PROJECT_VERSION = 612;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\"";
ENABLE_BITCODE = YES;
@@ -4273,7 +4376,11 @@
../../Qt/5.15.2/ios/include/QtMultimedia,
);
INFOPLIST_FILE = "watchkit Extension/Info.plist";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 2.13;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
@@ -4294,7 +4401,8 @@
PRODUCT_NAME = "${TARGET_NAME}";
SDKROOT = watchos;
SKIP_INSTALL = YES;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = 4;
VALIDATE_PRODUCT = YES;

View File

@@ -87,8 +87,6 @@
</RemoteRunnable>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "876E4E102594747F00BD5714"
BuildableName = "watchkit.app"
BlueprintName = "watchkit"
ReferencedContainer = "container:qdomyoszwift.xcodeproj">

View File

@@ -12,3 +12,4 @@ ANDROID_PACKAGE_SOURCE_DIR = $$PWD/src/android
ANDROID_ABIS = armeabi-v7a arm64-v8a x86 x86_64
#QMAKE_CXXFLAGS += -Werror=suggest-override

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,449 @@
/* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#ifndef http_parser_h
#define http_parser_h
#ifdef __cplusplus
extern "C" {
#endif
/* Also update SONAME in the Makefile whenever you change these. */
#define HTTP_PARSER_VERSION_MAJOR 2
#define HTTP_PARSER_VERSION_MINOR 9
#define HTTP_PARSER_VERSION_PATCH 4
#include <stddef.h>
#if defined(_WIN32) && !defined(__MINGW32__) && \
(!defined(_MSC_VER) || _MSC_VER<1600) && !defined(__WINE__)
#include <BaseTsd.h>
typedef __int8 int8_t;
typedef unsigned __int8 uint8_t;
typedef __int16 int16_t;
typedef unsigned __int16 uint16_t;
typedef __int32 int32_t;
typedef unsigned __int32 uint32_t;
typedef __int64 int64_t;
typedef unsigned __int64 uint64_t;
#elif (defined(__sun) || defined(__sun__)) && defined(__SunOS_5_9)
#include <sys/inttypes.h>
#else
#include <stdint.h>
#endif
/* Compile with -DHTTP_PARSER_STRICT=0 to make less checks, but run
* faster
*/
#ifndef HTTP_PARSER_STRICT
# define HTTP_PARSER_STRICT 1
#endif
/* Maximium header size allowed. If the macro is not defined
* before including this header then the default is used. To
* change the maximum header size, define the macro in the build
* environment (e.g. -DHTTP_MAX_HEADER_SIZE=<value>). To remove
* the effective limit on the size of the header, define the macro
* to a very large number (e.g. -DHTTP_MAX_HEADER_SIZE=0x7fffffff)
*/
#ifndef HTTP_MAX_HEADER_SIZE
# define HTTP_MAX_HEADER_SIZE (80*1024)
#endif
typedef struct http_parser http_parser;
typedef struct http_parser_settings http_parser_settings;
/* Callbacks should return non-zero to indicate an error. The parser will
* then halt execution.
*
* The one exception is on_headers_complete. In a HTTP_RESPONSE parser
* returning '1' from on_headers_complete will tell the parser that it
* should not expect a body. This is used when receiving a response to a
* HEAD request which may contain 'Content-Length' or 'Transfer-Encoding:
* chunked' headers that indicate the presence of a body.
*
* Returning `2` from on_headers_complete will tell parser that it should not
* expect neither a body nor any futher responses on this connection. This is
* useful for handling responses to a CONNECT request which may not contain
* `Upgrade` or `Connection: upgrade` headers.
*
* http_data_cb does not return data chunks. It will be called arbitrarily
* many times for each string. E.G. you might get 10 callbacks for "on_url"
* each providing just a few characters more data.
*/
typedef int (*http_data_cb) (http_parser*, const char *at, size_t length);
typedef int (*http_cb) (http_parser*);
/* Status Codes */
#define HTTP_STATUS_MAP(XX) \
XX(100, CONTINUE, Continue) \
XX(101, SWITCHING_PROTOCOLS, Switching Protocols) \
XX(102, PROCESSING, Processing) \
XX(200, OK, OK) \
XX(201, CREATED, Created) \
XX(202, ACCEPTED, Accepted) \
XX(203, NON_AUTHORITATIVE_INFORMATION, Non-Authoritative Information) \
XX(204, NO_CONTENT, No Content) \
XX(205, RESET_CONTENT, Reset Content) \
XX(206, PARTIAL_CONTENT, Partial Content) \
XX(207, MULTI_STATUS, Multi-Status) \
XX(208, ALREADY_REPORTED, Already Reported) \
XX(226, IM_USED, IM Used) \
XX(300, MULTIPLE_CHOICES, Multiple Choices) \
XX(301, MOVED_PERMANENTLY, Moved Permanently) \
XX(302, FOUND, Found) \
XX(303, SEE_OTHER, See Other) \
XX(304, NOT_MODIFIED, Not Modified) \
XX(305, USE_PROXY, Use Proxy) \
XX(307, TEMPORARY_REDIRECT, Temporary Redirect) \
XX(308, PERMANENT_REDIRECT, Permanent Redirect) \
XX(400, BAD_REQUEST, Bad Request) \
XX(401, UNAUTHORIZED, Unauthorized) \
XX(402, PAYMENT_REQUIRED, Payment Required) \
XX(403, FORBIDDEN, Forbidden) \
XX(404, NOT_FOUND, Not Found) \
XX(405, METHOD_NOT_ALLOWED, Method Not Allowed) \
XX(406, NOT_ACCEPTABLE, Not Acceptable) \
XX(407, PROXY_AUTHENTICATION_REQUIRED, Proxy Authentication Required) \
XX(408, REQUEST_TIMEOUT, Request Timeout) \
XX(409, CONFLICT, Conflict) \
XX(410, GONE, Gone) \
XX(411, LENGTH_REQUIRED, Length Required) \
XX(412, PRECONDITION_FAILED, Precondition Failed) \
XX(413, PAYLOAD_TOO_LARGE, Payload Too Large) \
XX(414, URI_TOO_LONG, URI Too Long) \
XX(415, UNSUPPORTED_MEDIA_TYPE, Unsupported Media Type) \
XX(416, RANGE_NOT_SATISFIABLE, Range Not Satisfiable) \
XX(417, EXPECTATION_FAILED, Expectation Failed) \
XX(421, MISDIRECTED_REQUEST, Misdirected Request) \
XX(422, UNPROCESSABLE_ENTITY, Unprocessable Entity) \
XX(423, LOCKED, Locked) \
XX(424, FAILED_DEPENDENCY, Failed Dependency) \
XX(426, UPGRADE_REQUIRED, Upgrade Required) \
XX(428, PRECONDITION_REQUIRED, Precondition Required) \
XX(429, TOO_MANY_REQUESTS, Too Many Requests) \
XX(431, REQUEST_HEADER_FIELDS_TOO_LARGE, Request Header Fields Too Large) \
XX(451, UNAVAILABLE_FOR_LEGAL_REASONS, Unavailable For Legal Reasons) \
XX(500, INTERNAL_SERVER_ERROR, Internal Server Error) \
XX(501, NOT_IMPLEMENTED, Not Implemented) \
XX(502, BAD_GATEWAY, Bad Gateway) \
XX(503, SERVICE_UNAVAILABLE, Service Unavailable) \
XX(504, GATEWAY_TIMEOUT, Gateway Timeout) \
XX(505, HTTP_VERSION_NOT_SUPPORTED, HTTP Version Not Supported) \
XX(506, VARIANT_ALSO_NEGOTIATES, Variant Also Negotiates) \
XX(507, INSUFFICIENT_STORAGE, Insufficient Storage) \
XX(508, LOOP_DETECTED, Loop Detected) \
XX(510, NOT_EXTENDED, Not Extended) \
XX(511, NETWORK_AUTHENTICATION_REQUIRED, Network Authentication Required) \
enum http_status
{
#define XX(num, name, string) HTTP_STATUS_##name = num,
HTTP_STATUS_MAP(XX)
#undef XX
};
/* Request Methods */
#define HTTP_METHOD_MAP(XX) \
XX(0, DELETE, DELETE) \
XX(1, GET, GET) \
XX(2, HEAD, HEAD) \
XX(3, POST, POST) \
XX(4, PUT, PUT) \
/* pathological */ \
XX(5, CONNECT, CONNECT) \
XX(6, OPTIONS, OPTIONS) \
XX(7, TRACE, TRACE) \
/* WebDAV */ \
XX(8, COPY, COPY) \
XX(9, LOCK, LOCK) \
XX(10, MKCOL, MKCOL) \
XX(11, MOVE, MOVE) \
XX(12, PROPFIND, PROPFIND) \
XX(13, PROPPATCH, PROPPATCH) \
XX(14, SEARCH, SEARCH) \
XX(15, UNLOCK, UNLOCK) \
XX(16, BIND, BIND) \
XX(17, REBIND, REBIND) \
XX(18, UNBIND, UNBIND) \
XX(19, ACL, ACL) \
/* subversion */ \
XX(20, REPORT, REPORT) \
XX(21, MKACTIVITY, MKACTIVITY) \
XX(22, CHECKOUT, CHECKOUT) \
XX(23, MERGE, MERGE) \
/* upnp */ \
XX(24, MSEARCH, M-SEARCH) \
XX(25, NOTIFY, NOTIFY) \
XX(26, SUBSCRIBE, SUBSCRIBE) \
XX(27, UNSUBSCRIBE, UNSUBSCRIBE) \
/* RFC-5789 */ \
XX(28, PATCH, PATCH) \
XX(29, PURGE, PURGE) \
/* CalDAV */ \
XX(30, MKCALENDAR, MKCALENDAR) \
/* RFC-2068, section 19.6.1.2 */ \
XX(31, LINK, LINK) \
XX(32, UNLINK, UNLINK) \
/* icecast */ \
XX(33, SOURCE, SOURCE) \
enum http_method
{
#define XX(num, name, string) HTTP_##name = num,
HTTP_METHOD_MAP(XX)
#undef XX
};
enum http_parser_type { HTTP_REQUEST, HTTP_RESPONSE, HTTP_BOTH };
/* Flag values for http_parser.flags field */
enum flags
{ F_CHUNKED = 1 << 0
, F_CONNECTION_KEEP_ALIVE = 1 << 1
, F_CONNECTION_CLOSE = 1 << 2
, F_CONNECTION_UPGRADE = 1 << 3
, F_TRAILING = 1 << 4
, F_UPGRADE = 1 << 5
, F_SKIPBODY = 1 << 6
, F_CONTENTLENGTH = 1 << 7
};
/* Map for errno-related constants
*
* The provided argument should be a macro that takes 2 arguments.
*/
#define HTTP_ERRNO_MAP(XX) \
/* No error */ \
XX(OK, "success") \
\
/* Callback-related errors */ \
XX(CB_message_begin, "the on_message_begin callback failed") \
XX(CB_url, "the on_url callback failed") \
XX(CB_header_field, "the on_header_field callback failed") \
XX(CB_header_value, "the on_header_value callback failed") \
XX(CB_headers_complete, "the on_headers_complete callback failed") \
XX(CB_body, "the on_body callback failed") \
XX(CB_message_complete, "the on_message_complete callback failed") \
XX(CB_status, "the on_status callback failed") \
XX(CB_chunk_header, "the on_chunk_header callback failed") \
XX(CB_chunk_complete, "the on_chunk_complete callback failed") \
\
/* Parsing-related errors */ \
XX(INVALID_EOF_STATE, "stream ended at an unexpected time") \
XX(HEADER_OVERFLOW, \
"too many header bytes seen; overflow detected") \
XX(CLOSED_CONNECTION, \
"data received after completed connection: close message") \
XX(INVALID_VERSION, "invalid HTTP version") \
XX(INVALID_STATUS, "invalid HTTP status code") \
XX(INVALID_METHOD, "invalid HTTP method") \
XX(INVALID_URL, "invalid URL") \
XX(INVALID_HOST, "invalid host") \
XX(INVALID_PORT, "invalid port") \
XX(INVALID_PATH, "invalid path") \
XX(INVALID_QUERY_STRING, "invalid query string") \
XX(INVALID_FRAGMENT, "invalid fragment") \
XX(LF_EXPECTED, "LF character expected") \
XX(INVALID_HEADER_TOKEN, "invalid character in header") \
XX(INVALID_CONTENT_LENGTH, \
"invalid character in content-length header") \
XX(UNEXPECTED_CONTENT_LENGTH, \
"unexpected content-length header") \
XX(INVALID_CHUNK_SIZE, \
"invalid character in chunk size header") \
XX(INVALID_CONSTANT, "invalid constant string") \
XX(INVALID_INTERNAL_STATE, "encountered unexpected internal state")\
XX(STRICT, "strict mode assertion failed") \
XX(PAUSED, "parser is paused") \
XX(UNKNOWN, "an unknown error occurred") \
XX(INVALID_TRANSFER_ENCODING, \
"request has invalid transfer-encoding") \
/* Define HPE_* values for each errno value above */
#define HTTP_ERRNO_GEN(n, s) HPE_##n,
enum http_errno {
HTTP_ERRNO_MAP(HTTP_ERRNO_GEN)
};
#undef HTTP_ERRNO_GEN
/* Get an http_errno value from an http_parser */
#define HTTP_PARSER_ERRNO(p) ((enum http_errno) (p)->http_errno)
struct http_parser {
/** PRIVATE **/
unsigned int type : 2; /* enum http_parser_type */
unsigned int flags : 8; /* F_* values from 'flags' enum; semi-public */
unsigned int state : 7; /* enum state from http_parser.c */
unsigned int header_state : 7; /* enum header_state from http_parser.c */
unsigned int index : 5; /* index into current matcher */
unsigned int uses_transfer_encoding : 1; /* Transfer-Encoding header is present */
unsigned int allow_chunked_length : 1; /* Allow headers with both
* `Content-Length` and
* `Transfer-Encoding: chunked` set */
unsigned int lenient_http_headers : 1;
uint32_t nread; /* # bytes read in various scenarios */
uint64_t content_length; /* # bytes in body. `(uint64_t) -1` (all bits one)
* if no Content-Length header.
*/
/** READ-ONLY **/
unsigned short http_major;
unsigned short http_minor;
unsigned int status_code : 16; /* responses only */
unsigned int method : 8; /* requests only */
unsigned int http_errno : 7;
/* 1 = Upgrade header was present and the parser has exited because of that.
* 0 = No upgrade header present.
* Should be checked when http_parser_execute() returns in addition to
* error checking.
*/
unsigned int upgrade : 1;
/** PUBLIC **/
void *data; /* A pointer to get hook to the "connection" or "socket" object */
};
struct http_parser_settings {
http_cb on_message_begin;
http_data_cb on_url;
http_data_cb on_status;
http_data_cb on_header_field;
http_data_cb on_header_value;
http_cb on_headers_complete;
http_data_cb on_body;
http_cb on_message_complete;
/* When on_chunk_header is called, the current chunk length is stored
* in parser->content_length.
*/
http_cb on_chunk_header;
http_cb on_chunk_complete;
};
enum http_parser_url_fields
{ UF_SCHEMA = 0
, UF_HOST = 1
, UF_PORT = 2
, UF_PATH = 3
, UF_QUERY = 4
, UF_FRAGMENT = 5
, UF_USERINFO = 6
, UF_MAX = 7
};
/* Result structure for http_parser_parse_url().
*
* Callers should index into field_data[] with UF_* values iff field_set
* has the relevant (1 << UF_*) bit set. As a courtesy to clients (and
* because we probably have padding left over), we convert any port to
* a uint16_t.
*/
struct http_parser_url {
uint16_t field_set; /* Bitmask of (1 << UF_*) values */
uint16_t port; /* Converted UF_PORT string */
struct {
uint16_t off; /* Offset into buffer in which field starts */
uint16_t len; /* Length of run in buffer */
} field_data[UF_MAX];
};
/* Returns the library version. Bits 16-23 contain the major version number,
* bits 8-15 the minor version number and bits 0-7 the patch level.
* Usage example:
*
* unsigned long version = http_parser_version();
* unsigned major = (version >> 16) & 255;
* unsigned minor = (version >> 8) & 255;
* unsigned patch = version & 255;
* printf("http_parser v%u.%u.%u\n", major, minor, patch);
*/
unsigned long http_parser_version(void);
void http_parser_init(http_parser *parser, enum http_parser_type type);
/* Initialize http_parser_settings members to 0
*/
void http_parser_settings_init(http_parser_settings *settings);
/* Executes the parser. Returns number of parsed bytes. Sets
* `parser->http_errno` on error. */
size_t http_parser_execute(http_parser *parser,
const http_parser_settings *settings,
const char *data,
size_t len);
/* If http_should_keep_alive() in the on_headers_complete or
* on_message_complete callback returns 0, then this should be
* the last message on the connection.
* If you are the server, respond with the "Connection: close" header.
* If you are the client, close the connection.
*/
int http_should_keep_alive(const http_parser *parser);
/* Returns a string version of the HTTP method. */
const char *http_method_str(enum http_method m);
/* Returns a string version of the HTTP status code. */
const char *http_status_str(enum http_status s);
/* Return a string name of the given error */
const char *http_errno_name(enum http_errno err);
/* Return a string description of the given error */
const char *http_errno_description(enum http_errno err);
/* Initialize all http_parser_url members to 0 */
void http_parser_url_init(struct http_parser_url *u);
/* Parse a URL; return nonzero on failure */
int http_parser_parse_url(const char *buf, size_t buflen,
int is_connect,
struct http_parser_url *u);
/* Pause or un-pause the parser; a nonzero value pauses */
void http_parser_pause(http_parser *parser, int paused);
/* Checks if this is the final chunk of the body. */
int http_body_is_final(const http_parser *parser);
/* Change the maximum header size provided at compile time. */
void http_parser_set_max_header_size(uint32_t size);
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -1,7 +1,7 @@
TEMPLATE = subdirs
CONFIG+=ordered
!android: {
!ios: !android: {
SUBDIRS = \
src/qdomyos-zwift-lib.pro \
src/qdomyos-zwift.pro \
@@ -10,9 +10,15 @@ SUBDIRS = \
tst.depends = src/qdomyos-zwift-lib.pro
}
android: {
android: {
SUBDIRS = \
src/qdomyos-zwift.pro
}
ios: {
SUBDIRS = \
src/qdomyos-zwift-lib.pro \
src/qdomyos-zwift.pro
}

Binary file not shown.

View File

@@ -380,7 +380,7 @@ void Computrainer::unpackTelemetry(int &ss1, int &ss2, int &ss3, int &buttons, i
* READING TELEMETRY AND ISSUING CONTROL COMMANDS WHILST UPDATING
* MEMBER VARIABLES AS TELEMETRY CHANGES ARE FOUND.
*
* run() - bg thread continuosly reading/writing the device port
* run() - bg thread continuously reading/writing the device port
* it is kicked off by start and then examines status to check
* when it is time to pause or stop altogether.
* ---------------------------------------------------------------------- */

View File

@@ -145,7 +145,7 @@ class Computrainer : public QThread {
double getLoad();
private:
void run(); // called by start to kick off the CT comtrol thread
void run() override; // called by start to kick off the CT comtrol thread
// 56 bytes comprise of 8 7byte command messages, where
// the last is the set load / gradient respectively

View File

@@ -0,0 +1,41 @@
<?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>AvailableLibraries</key>
<array>
<dict>
<key>LibraryIdentifier</key>
<string>ios-armv7_arm64</string>
<key>LibraryPath</key>
<string>ConnectIQ.framework</string>
<key>SupportedArchitectures</key>
<array>
<string>armv7</string>
<string>arm64</string>
</array>
<key>SupportedPlatform</key>
<string>ios</string>
</dict>
<dict>
<key>LibraryIdentifier</key>
<string>ios-i386_x86_64-simulator</string>
<key>LibraryPath</key>
<string>ConnectIQ.framework</string>
<key>SupportedArchitectures</key>
<array>
<string>i386</string>
<string>x86_64</string>
</array>
<key>SupportedPlatform</key>
<string>ios</string>
<key>SupportedPlatformVariant</key>
<string>simulator</string>
</dict>
</array>
<key>CFBundlePackageType</key>
<string>XFWK</string>
<key>XCFrameworkFormatVersion</key>
<string>1.0</string>
</dict>
</plist>

View File

@@ -0,0 +1,237 @@
//
// ConnectIQ.h
// ConnectIQ
//
// Copyright (c) 2014 Garmin. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "IQConstants.h"
#import "IQDevice.h"
#import "IQApp.h"
// --------------------------------------------------------------------------------
#pragma mark - PUBLIC TYPES
// --------------------------------------------------------------------------------
/// @brief SendMessage progress callback block
///
/// @param sentBytes The number of bytes that have been successfully transferred
/// to the device so far for this connection.
/// @param totalBytes The total number of bytes to transfer for this connection.
typedef void (^IQSendMessageProgress)(uint32_t sentBytes, uint32_t totalBytes);
/// @brief SendMessage completion callback block
///
/// @param result The result of the SendMessage operation.
typedef void (^IQSendMessageCompletion)(IQSendMessageResult result);
/// @brief Conforming to the IQUIOverrideDelegate protocol indicates that an
/// object handles one or more events triggered by the ConnectIQ SDK that
/// require user input.
@protocol IQUIOverrideDelegate <NSObject>
@optional
/// @brief Called by the ConnectIQ SDK when an action has been requested that
/// requires Garmin Connect Mobile to be installed.
///
/// The receiver should choose whether or not to launch the Apple App
/// Store page for GCM, ideally by presenting the user with a choice.
///
/// If the receiver of this message decides to install GCM, it must call
/// showAppStoreForConnectMobile.
- (void)needsToInstallConnectMobile;
@end
/// @brief Conforming to the IQDeviceEventDelegate protocol indicates that an
/// object handles ConnectIQ device status events.
@protocol IQDeviceEventDelegate <NSObject>
@optional
/// @brief Called by the ConnectIQ SDK when an IQDevice's connection status has
/// changed.
///
/// @param device The IQDevice whose status changed.
/// @param status The new status of the device.
- (void)deviceStatusChanged:(IQDevice *)device status:(IQDeviceStatus)status;
@end
/// @brief Conforming to the IQAppMessageDelegate protocol indicates that an
/// object handles messages from ConnectIQ apps on compatible devices.
@protocol IQAppMessageDelegate <NSObject>
@optional
/// @brief Called by the ConnectIQ SDK when a message is received from a device.
///
/// @param message The message that was received.
/// @param app The device app that sent the message.
- (void)receivedMessage:(id)message fromApp:(IQApp *)app;
@end
// --------------------------------------------------------------------------------
#pragma mark - CLASS DEFINITION
// --------------------------------------------------------------------------------
/// @brief The root of the ConnectIQ SDK API.
@interface ConnectIQ : NSObject
+ (instancetype)new NS_UNAVAILABLE;
- (instancetype)init NS_UNAVAILABLE;
// --------------------------------------------------------------------------------
#pragma mark - SINGLETON ACCESS
// --------------------------------------------------------------------------------
/// @brief Exposes the single static instance of the ConnectIQ class.
///
/// @return The single status instance of the ConnectIQ class.
+ (ConnectIQ *)sharedInstance;
// --------------------------------------------------------------------------------
#pragma mark - INITIALIZATION
// --------------------------------------------------------------------------------
/// @brief Initializes the ConnectIQ SDK with startup parameters necessary for
/// its operation.
///
/// @param urlScheme The URL scheme for this companion app. When Garmin Connect
/// Mobile is launched, it will return to the companion app by
/// launching a URL with this scheme.
/// @param delegate The delegate that the SDK will use for notifying the
/// companion app about events that require user input. If this
/// is nil, the SDK's default UI will be used.
- (void)initializeWithUrlScheme:(NSString *)urlScheme uiOverrideDelegate:(id<IQUIOverrideDelegate>)delegate;
// --------------------------------------------------------------------------------
#pragma mark - EXTERNAL LAUNCHING
// --------------------------------------------------------------------------------
/// @brief Launches the Apple App Store page for the Garmin Connect Mobile app.
/// The companion app should only call this in response to a
/// needsToInstallConnectMobile event that gets triggered on the
/// IQUIOverrideDelegate.
- (void)showAppStoreForConnectMobile;
/// @brief Launches Garmin Connect Mobile for the purpose of retrieving a list of
/// ConnectIQ-compatible devices.
///
/// Once the user has chosen which ConnectIQ devices to share with the
/// companion app, GCM will return those devices to the companion app by
/// opening a URL with the scheme registered in
/// initializeWithUrlScheme:uiOverrideDelegate:.
///
/// The companion app should handle this URL by passing it in to the
/// parseDeviceSelectionResponseFromURL: method to get the list of devices
/// that the user permitted the companion app to communicate with.
- (void)showConnectIQDeviceSelection;
/// @brief Parses a URL opened from Garmin Connect Mobile into a list of devices.
///
/// @param url The URL to parse.
///
/// @return An array of IQDevice objects representing the ConnectIQ-compatible
/// devices that the user allowed GCM to share with the companion app.
///
/// @seealso showConnectIQDeviceSelection
- (NSArray *)parseDeviceSelectionResponseFromURL:(NSURL *)url;
/// @brief Launches Garmin Connect Mobile and shows the ConnectIQ app store page
/// for the given app.
///
/// The companion app should call this if the user would like to manage
/// the app on the device, such as to install, upgrade, uninstall, or
/// modify settings.
///
/// @param app The app to show the ConnectIQ app store page for.
- (void)showConnectIQStoreForApp:(IQApp *)app;
// --------------------------------------------------------------------------------
#pragma mark - DEVICE MANAGEMENT
// --------------------------------------------------------------------------------
/// @brief Registers an object as a listener for ConnectIQ device status events.
///
/// A device may have multiple device event listeners if this method is
/// called more than once.
///
/// @param device A device to listen for status events from.
/// @param delegate The listener which will receive status events for this device.
- (void)registerForDeviceEvents:(IQDevice *)device delegate:(id<IQDeviceEventDelegate>)delegate;
/// @brief Unregisters a listener for a specific device.
///
/// @param device The device to unregister the listener for.
/// @param delegate The listener to remove from the device.
- (void)unregisterForDeviceEvents:(IQDevice *)device delegate:(id<IQDeviceEventDelegate>)delegate;
/// @brief Unregisters the specified listener from all devices for which it had
/// previously been registered.
///
/// @param delegate The listener to unregister.
- (void)unregisterForAllDeviceEvents:(id<IQDeviceEventDelegate>)delegate;
/// @brief Gets the current connection status of a device.
///
/// The device must have been registered for event notifications by
/// calling registerForDeviceEvents:delegate: or this method will return
/// IQDeviceStatus_InvalidDevice.
///
/// @param device The device to get the status for.
///
/// @return The device's current connection status.
- (IQDeviceStatus)getDeviceStatus:(IQDevice *)device;
// --------------------------------------------------------------------------------
#pragma mark - APP MANAGEMENT
// --------------------------------------------------------------------------------
/// @brief Begins getting the status of an app on a device. This method returns
/// immediately.
///
/// @param app The IQApp to get the status for.
/// @param completion The completion block that will be triggered when the device
/// status operation is complete.
- (void)getAppStatus:(IQApp *)app completion:(void(^)(IQAppStatus *appStatus))completion;
/// @brief Registers an object as a listener for ConnectIQ messages from an app
/// on a device.
///
/// An app may have multiple message listeners if this method is called
/// more than once.
///
/// @param app The app to listen for messages from.
/// @param delegate The listener which will receive messages for this app.
- (void)registerForAppMessages:(IQApp *)app delegate:(id<IQAppMessageDelegate>)delegate;
/// @brief Unregisters a listener for a specific app.
///
/// @param app The app to unregister a listener for.
/// @param delegate The listener to remove from the app.
- (void)unregisterForAppMessages:(IQApp *)app delegate:(id<IQAppMessageDelegate>)delegate;
/// @brief Unregisters all previously registered apps for a specific listener.
///
/// @param delegate The listener to unregister.
- (void)unregisterForAllAppMessages:(id<IQAppMessageDelegate>)delegate;
/// @brief Begins sending a message to an app. This method returns immediately.
///
/// @param message The message to send to the app. This message must be one of
/// the following types: NSString, NSNumber, NSNull, NSArray,
/// or NSDictionary. Arrays and dictionaries may be nested.
/// @param app The app to send the message to.
/// @param progress A progress block that will be triggered periodically
/// throughout the transfer. This is guaranteed to be triggered
/// at least once.
/// @param completion A completion block that will be triggered when the send
/// message operation is complete.
- (void)sendMessage:(id)message toApp:(IQApp *)app progress:(IQSendMessageProgress)progress completion:(IQSendMessageCompletion)completion;
/// @brief Sends an open app request message request to the device. This method returns immediately.
///
/// @param app The app to open.
/// @param completion A completion block that will be triggered when the send
/// message operation is complete.
- (void)openAppRequest:(IQApp *)app completion:(IQSendMessageCompletion)completion;
// TODO *** Holding off on documenting this until this method actually works.
- (void)sendImage:(NSData *)bitmap toApp:(IQApp *)app progress:(IQSendMessageProgress)progress completion:(IQSendMessageCompletion)completion;
@end

View File

@@ -0,0 +1,34 @@
//
// IQApp.h
// ConnectIQ
//
// Copyright (c) 2014 Garmin. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "IQDevice.h"
#import "IQAppStatus.h"
/// @brief Represents an instance of a ConnectIQ app that is installed on a
/// Garmin device.
@interface IQApp : NSObject <NSSecureCoding>
/// @brief The unique identifier for this app.
@property (nonatomic, readonly) NSUUID *uuid;
/// @brief The unique identifier for this app in the store.
@property (nonatomic, readonly) NSUUID *storeUuid;
/// @brief The device that this app is installed on.
@property (nonatomic, readonly) IQDevice *device;
/// @brief Creates a new app instance.
///
/// @param uuid The UUID of the app to create.
/// @param storeUuid The store UUID of the app to create.
/// @param device The device the app to create is installed on.
///
/// @return A new IQApp instance with the appropriate values set.
+ (IQApp *)appWithUUID:(NSUUID *)uuid storeUuid:(NSUUID *)storeUuid device:(IQDevice *)device;
@end

View File

@@ -0,0 +1,20 @@
//
// IQAppStatus.h
// ConnectIQ
//
// Copyright (c) 2014 Garmin. All rights reserved.
//
#import <Foundation/Foundation.h>
/// @brief Represents the current status of an app on a Garmin device.
@interface IQAppStatus : NSObject
/// @brief YES if the app is installed on the device, NO if it isn't.
@property (nonatomic, readonly) BOOL isInstalled;
/// @brief The version of the app that is currently installed on the device. If
/// the app is not installed, this value is unused.
@property (nonatomic, readonly) uint16_t version;
@end

View File

@@ -0,0 +1,63 @@
//
// IQConstants.h
// ConnectIQ
//
// Copyright (c) 2014 Garmin. All rights reserved.
//
#import <Foundation/Foundation.h>
/// @brief The current version of the ConnectIQ SDK.
extern int const IQSDKVersion;
/// @brief The bundle identifier for the Garmin Connect Mobile app.
extern NSString * const IQGCMBundle;
/// @brief The result of a SendMessage operation
typedef NS_ENUM(NSInteger, IQSendMessageResult){
///! @brief The message was sent successfully.
IQSendMessageResult_Success,
/// @brief The message failed to send due to an unknown error.
IQSendMessageResult_Failure_Unknown,
/// @brief The message failed to send. There was an error within the SDK or
/// on the device.
IQSendMessageResult_Failure_InternalError,
/// @brief The message failed to send. The device is not available right now.
IQSendMessageResult_Failure_DeviceNotAvailable,
/// @brief The message failed to send. The app is not installed on the
/// device.
IQSendMessageResult_Failure_AppNotFound,
/// @brief The message failed to send. The device is busy and cannot receive
/// the message right now.
IQSendMessageResult_Failure_DeviceIsBusy,
/// @brief The message failed to send. The message contained an unsupported
/// type.
IQSendMessageResult_Failure_UnsupportedType,
/// @brief The message failed to send. The device does not have enough memory
/// to receive the message.
IQSendMessageResult_Failure_InsufficientMemory,
/// @brief The message failed to send. The connection timed out while sending
/// the message.
IQSendMessageResult_Failure_Timeout,
/// @brief The message failed to send and was retried, but could not complete
/// after a number of tries.
IQSendMessageResult_Failure_MaxRetries,
/// @brief The message was received by the device but it chose not to display
/// a message prompt, ignoring the message.
IQSendMessageResult_Failure_PromptNotDisplayed,
/// @brief The message was received by the device but the app to open
/// was already running on the device.
IQSendMessageResult_Failure_AppAlreadyRunning,
};
NSString *NSStringFromSendMessageResult(IQSendMessageResult value);

View File

@@ -0,0 +1,61 @@
//
// IQDevice.h
// ConnectIQ
//
// Copyright (c) 2014 Garmin. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <CoreBluetooth/CoreBluetooth.h>
/// @brief The current status of an IQDevice.
typedef NS_ENUM(NSInteger, IQDeviceStatus){
/// @brief No device with this UUID has been registered for status events
/// the SDK.
IQDeviceStatus_InvalidDevice,
/// @brief Bluetooth is either powered off or resetting.
IQDeviceStatus_BluetoothNotReady,
/// @brief This device could not be found by iOS. Perhaps the user removed
/// the device?
IQDeviceStatus_NotFound,
/// @brief The device is recognized by iOS, but it is not currently
/// connected.
IQDeviceStatus_NotConnected,
/// @brief The device is connected and ready to communicate.
IQDeviceStatus_Connected,
};
/// @brief Represents a ConnectIQ-compatible Garmin device.
@interface IQDevice : NSObject <NSSecureCoding>
/// @brief The unique identifier for this device.
@property (nonatomic, readonly) NSUUID *uuid;
/// @brief The model name of the device provided by Garmin Connect Mobile.
@property (nonatomic, readonly) NSString *modelName;
/// @brief The friendly name of the device, set by the user and provided by
/// Garmin Connect Mobile.
@property (nonatomic, readonly) NSString *friendlyName;
/// @brief Creates a new device instance.
///
/// @param uuid The UUID of the device to create.
/// @param modelName The model name of the device to create.
/// @param friendlyName The friendly name of the device to create.
///
/// @return A new IQDevice instance with the appropriate values set.
+ (IQDevice *)deviceWithId:(NSUUID *)uuid modelName:(NSString *)modelName friendlyName:(NSString *)friendlyName;
/// @brief Creates a new device instance by copying another device's values.
///
/// @param device The device to copy values from.
///
/// @return A new IQDevice instance with all values copied.
- (instancetype)initWithDevice:(IQDevice *)device;
@end

View File

@@ -0,0 +1,6 @@
framework module ConnectIQ {
umbrella header "ConnectIQ.h"
export *
module * { export * }
}

View File

@@ -0,0 +1,237 @@
//
// ConnectIQ.h
// ConnectIQ
//
// Copyright (c) 2014 Garmin. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "IQConstants.h"
#import "IQDevice.h"
#import "IQApp.h"
// --------------------------------------------------------------------------------
#pragma mark - PUBLIC TYPES
// --------------------------------------------------------------------------------
/// @brief SendMessage progress callback block
///
/// @param sentBytes The number of bytes that have been successfully transferred
/// to the device so far for this connection.
/// @param totalBytes The total number of bytes to transfer for this connection.
typedef void (^IQSendMessageProgress)(uint32_t sentBytes, uint32_t totalBytes);
/// @brief SendMessage completion callback block
///
/// @param result The result of the SendMessage operation.
typedef void (^IQSendMessageCompletion)(IQSendMessageResult result);
/// @brief Conforming to the IQUIOverrideDelegate protocol indicates that an
/// object handles one or more events triggered by the ConnectIQ SDK that
/// require user input.
@protocol IQUIOverrideDelegate <NSObject>
@optional
/// @brief Called by the ConnectIQ SDK when an action has been requested that
/// requires Garmin Connect Mobile to be installed.
///
/// The receiver should choose whether or not to launch the Apple App
/// Store page for GCM, ideally by presenting the user with a choice.
///
/// If the receiver of this message decides to install GCM, it must call
/// showAppStoreForConnectMobile.
- (void)needsToInstallConnectMobile;
@end
/// @brief Conforming to the IQDeviceEventDelegate protocol indicates that an
/// object handles ConnectIQ device status events.
@protocol IQDeviceEventDelegate <NSObject>
@optional
/// @brief Called by the ConnectIQ SDK when an IQDevice's connection status has
/// changed.
///
/// @param device The IQDevice whose status changed.
/// @param status The new status of the device.
- (void)deviceStatusChanged:(IQDevice *)device status:(IQDeviceStatus)status;
@end
/// @brief Conforming to the IQAppMessageDelegate protocol indicates that an
/// object handles messages from ConnectIQ apps on compatible devices.
@protocol IQAppMessageDelegate <NSObject>
@optional
/// @brief Called by the ConnectIQ SDK when a message is received from a device.
///
/// @param message The message that was received.
/// @param app The device app that sent the message.
- (void)receivedMessage:(id)message fromApp:(IQApp *)app;
@end
// --------------------------------------------------------------------------------
#pragma mark - CLASS DEFINITION
// --------------------------------------------------------------------------------
/// @brief The root of the ConnectIQ SDK API.
@interface ConnectIQ : NSObject
+ (instancetype)new NS_UNAVAILABLE;
- (instancetype)init NS_UNAVAILABLE;
// --------------------------------------------------------------------------------
#pragma mark - SINGLETON ACCESS
// --------------------------------------------------------------------------------
/// @brief Exposes the single static instance of the ConnectIQ class.
///
/// @return The single status instance of the ConnectIQ class.
+ (ConnectIQ *)sharedInstance;
// --------------------------------------------------------------------------------
#pragma mark - INITIALIZATION
// --------------------------------------------------------------------------------
/// @brief Initializes the ConnectIQ SDK with startup parameters necessary for
/// its operation.
///
/// @param urlScheme The URL scheme for this companion app. When Garmin Connect
/// Mobile is launched, it will return to the companion app by
/// launching a URL with this scheme.
/// @param delegate The delegate that the SDK will use for notifying the
/// companion app about events that require user input. If this
/// is nil, the SDK's default UI will be used.
- (void)initializeWithUrlScheme:(NSString *)urlScheme uiOverrideDelegate:(id<IQUIOverrideDelegate>)delegate;
// --------------------------------------------------------------------------------
#pragma mark - EXTERNAL LAUNCHING
// --------------------------------------------------------------------------------
/// @brief Launches the Apple App Store page for the Garmin Connect Mobile app.
/// The companion app should only call this in response to a
/// needsToInstallConnectMobile event that gets triggered on the
/// IQUIOverrideDelegate.
- (void)showAppStoreForConnectMobile;
/// @brief Launches Garmin Connect Mobile for the purpose of retrieving a list of
/// ConnectIQ-compatible devices.
///
/// Once the user has chosen which ConnectIQ devices to share with the
/// companion app, GCM will return those devices to the companion app by
/// opening a URL with the scheme registered in
/// initializeWithUrlScheme:uiOverrideDelegate:.
///
/// The companion app should handle this URL by passing it in to the
/// parseDeviceSelectionResponseFromURL: method to get the list of devices
/// that the user permitted the companion app to communicate with.
- (void)showConnectIQDeviceSelection;
/// @brief Parses a URL opened from Garmin Connect Mobile into a list of devices.
///
/// @param url The URL to parse.
///
/// @return An array of IQDevice objects representing the ConnectIQ-compatible
/// devices that the user allowed GCM to share with the companion app.
///
/// @seealso showConnectIQDeviceSelection
- (NSArray *)parseDeviceSelectionResponseFromURL:(NSURL *)url;
/// @brief Launches Garmin Connect Mobile and shows the ConnectIQ app store page
/// for the given app.
///
/// The companion app should call this if the user would like to manage
/// the app on the device, such as to install, upgrade, uninstall, or
/// modify settings.
///
/// @param app The app to show the ConnectIQ app store page for.
- (void)showConnectIQStoreForApp:(IQApp *)app;
// --------------------------------------------------------------------------------
#pragma mark - DEVICE MANAGEMENT
// --------------------------------------------------------------------------------
/// @brief Registers an object as a listener for ConnectIQ device status events.
///
/// A device may have multiple device event listeners if this method is
/// called more than once.
///
/// @param device A device to listen for status events from.
/// @param delegate The listener which will receive status events for this device.
- (void)registerForDeviceEvents:(IQDevice *)device delegate:(id<IQDeviceEventDelegate>)delegate;
/// @brief Unregisters a listener for a specific device.
///
/// @param device The device to unregister the listener for.
/// @param delegate The listener to remove from the device.
- (void)unregisterForDeviceEvents:(IQDevice *)device delegate:(id<IQDeviceEventDelegate>)delegate;
/// @brief Unregisters the specified listener from all devices for which it had
/// previously been registered.
///
/// @param delegate The listener to unregister.
- (void)unregisterForAllDeviceEvents:(id<IQDeviceEventDelegate>)delegate;
/// @brief Gets the current connection status of a device.
///
/// The device must have been registered for event notifications by
/// calling registerForDeviceEvents:delegate: or this method will return
/// IQDeviceStatus_InvalidDevice.
///
/// @param device The device to get the status for.
///
/// @return The device's current connection status.
- (IQDeviceStatus)getDeviceStatus:(IQDevice *)device;
// --------------------------------------------------------------------------------
#pragma mark - APP MANAGEMENT
// --------------------------------------------------------------------------------
/// @brief Begins getting the status of an app on a device. This method returns
/// immediately.
///
/// @param app The IQApp to get the status for.
/// @param completion The completion block that will be triggered when the device
/// status operation is complete.
- (void)getAppStatus:(IQApp *)app completion:(void(^)(IQAppStatus *appStatus))completion;
/// @brief Registers an object as a listener for ConnectIQ messages from an app
/// on a device.
///
/// An app may have multiple message listeners if this method is called
/// more than once.
///
/// @param app The app to listen for messages from.
/// @param delegate The listener which will receive messages for this app.
- (void)registerForAppMessages:(IQApp *)app delegate:(id<IQAppMessageDelegate>)delegate;
/// @brief Unregisters a listener for a specific app.
///
/// @param app The app to unregister a listener for.
/// @param delegate The listener to remove from the app.
- (void)unregisterForAppMessages:(IQApp *)app delegate:(id<IQAppMessageDelegate>)delegate;
/// @brief Unregisters all previously registered apps for a specific listener.
///
/// @param delegate The listener to unregister.
- (void)unregisterForAllAppMessages:(id<IQAppMessageDelegate>)delegate;
/// @brief Begins sending a message to an app. This method returns immediately.
///
/// @param message The message to send to the app. This message must be one of
/// the following types: NSString, NSNumber, NSNull, NSArray,
/// or NSDictionary. Arrays and dictionaries may be nested.
/// @param app The app to send the message to.
/// @param progress A progress block that will be triggered periodically
/// throughout the transfer. This is guaranteed to be triggered
/// at least once.
/// @param completion A completion block that will be triggered when the send
/// message operation is complete.
- (void)sendMessage:(id)message toApp:(IQApp *)app progress:(IQSendMessageProgress)progress completion:(IQSendMessageCompletion)completion;
/// @brief Sends an open app request message request to the device. This method returns immediately.
///
/// @param app The app to open.
/// @param completion A completion block that will be triggered when the send
/// message operation is complete.
- (void)openAppRequest:(IQApp *)app completion:(IQSendMessageCompletion)completion;
// TODO *** Holding off on documenting this until this method actually works.
- (void)sendImage:(NSData *)bitmap toApp:(IQApp *)app progress:(IQSendMessageProgress)progress completion:(IQSendMessageCompletion)completion;
@end

View File

@@ -0,0 +1,34 @@
//
// IQApp.h
// ConnectIQ
//
// Copyright (c) 2014 Garmin. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "IQDevice.h"
#import "IQAppStatus.h"
/// @brief Represents an instance of a ConnectIQ app that is installed on a
/// Garmin device.
@interface IQApp : NSObject <NSSecureCoding>
/// @brief The unique identifier for this app.
@property (nonatomic, readonly) NSUUID *uuid;
/// @brief The unique identifier for this app in the store.
@property (nonatomic, readonly) NSUUID *storeUuid;
/// @brief The device that this app is installed on.
@property (nonatomic, readonly) IQDevice *device;
/// @brief Creates a new app instance.
///
/// @param uuid The UUID of the app to create.
/// @param storeUuid The store UUID of the app to create.
/// @param device The device the app to create is installed on.
///
/// @return A new IQApp instance with the appropriate values set.
+ (IQApp *)appWithUUID:(NSUUID *)uuid storeUuid:(NSUUID *)storeUuid device:(IQDevice *)device;
@end

View File

@@ -0,0 +1,20 @@
//
// IQAppStatus.h
// ConnectIQ
//
// Copyright (c) 2014 Garmin. All rights reserved.
//
#import <Foundation/Foundation.h>
/// @brief Represents the current status of an app on a Garmin device.
@interface IQAppStatus : NSObject
/// @brief YES if the app is installed on the device, NO if it isn't.
@property (nonatomic, readonly) BOOL isInstalled;
/// @brief The version of the app that is currently installed on the device. If
/// the app is not installed, this value is unused.
@property (nonatomic, readonly) uint16_t version;
@end

View File

@@ -0,0 +1,63 @@
//
// IQConstants.h
// ConnectIQ
//
// Copyright (c) 2014 Garmin. All rights reserved.
//
#import <Foundation/Foundation.h>
/// @brief The current version of the ConnectIQ SDK.
extern int const IQSDKVersion;
/// @brief The bundle identifier for the Garmin Connect Mobile app.
extern NSString * const IQGCMBundle;
/// @brief The result of a SendMessage operation
typedef NS_ENUM(NSInteger, IQSendMessageResult){
///! @brief The message was sent successfully.
IQSendMessageResult_Success,
/// @brief The message failed to send due to an unknown error.
IQSendMessageResult_Failure_Unknown,
/// @brief The message failed to send. There was an error within the SDK or
/// on the device.
IQSendMessageResult_Failure_InternalError,
/// @brief The message failed to send. The device is not available right now.
IQSendMessageResult_Failure_DeviceNotAvailable,
/// @brief The message failed to send. The app is not installed on the
/// device.
IQSendMessageResult_Failure_AppNotFound,
/// @brief The message failed to send. The device is busy and cannot receive
/// the message right now.
IQSendMessageResult_Failure_DeviceIsBusy,
/// @brief The message failed to send. The message contained an unsupported
/// type.
IQSendMessageResult_Failure_UnsupportedType,
/// @brief The message failed to send. The device does not have enough memory
/// to receive the message.
IQSendMessageResult_Failure_InsufficientMemory,
/// @brief The message failed to send. The connection timed out while sending
/// the message.
IQSendMessageResult_Failure_Timeout,
/// @brief The message failed to send and was retried, but could not complete
/// after a number of tries.
IQSendMessageResult_Failure_MaxRetries,
/// @brief The message was received by the device but it chose not to display
/// a message prompt, ignoring the message.
IQSendMessageResult_Failure_PromptNotDisplayed,
/// @brief The message was received by the device but the app to open
/// was already running on the device.
IQSendMessageResult_Failure_AppAlreadyRunning,
};
NSString *NSStringFromSendMessageResult(IQSendMessageResult value);

View File

@@ -0,0 +1,61 @@
//
// IQDevice.h
// ConnectIQ
//
// Copyright (c) 2014 Garmin. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <CoreBluetooth/CoreBluetooth.h>
/// @brief The current status of an IQDevice.
typedef NS_ENUM(NSInteger, IQDeviceStatus){
/// @brief No device with this UUID has been registered for status events
/// the SDK.
IQDeviceStatus_InvalidDevice,
/// @brief Bluetooth is either powered off or resetting.
IQDeviceStatus_BluetoothNotReady,
/// @brief This device could not be found by iOS. Perhaps the user removed
/// the device?
IQDeviceStatus_NotFound,
/// @brief The device is recognized by iOS, but it is not currently
/// connected.
IQDeviceStatus_NotConnected,
/// @brief The device is connected and ready to communicate.
IQDeviceStatus_Connected,
};
/// @brief Represents a ConnectIQ-compatible Garmin device.
@interface IQDevice : NSObject <NSSecureCoding>
/// @brief The unique identifier for this device.
@property (nonatomic, readonly) NSUUID *uuid;
/// @brief The model name of the device provided by Garmin Connect Mobile.
@property (nonatomic, readonly) NSString *modelName;
/// @brief The friendly name of the device, set by the user and provided by
/// Garmin Connect Mobile.
@property (nonatomic, readonly) NSString *friendlyName;
/// @brief Creates a new device instance.
///
/// @param uuid The UUID of the device to create.
/// @param modelName The model name of the device to create.
/// @param friendlyName The friendly name of the device to create.
///
/// @return A new IQDevice instance with the appropriate values set.
+ (IQDevice *)deviceWithId:(NSUUID *)uuid modelName:(NSString *)modelName friendlyName:(NSString *)friendlyName;
/// @brief Creates a new device instance by copying another device's values.
///
/// @param device The device to copy values from.
///
/// @return A new IQDevice instance with all values copied.
- (instancetype)initWithDevice:(IQDevice *)device;
@end

View File

@@ -0,0 +1,6 @@
framework module ConnectIQ {
umbrella header "ConnectIQ.h"
export *
module * { export * }
}

View File

@@ -0,0 +1,830 @@
<?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>files</key>
<dict>
<key>Headers/ConnectIQ.h</key>
<data>
F1hICh90Ex4ADEjYLcSi0YPhrPA=
</data>
<key>Headers/IQApp.h</key>
<data>
R7+SmeArgBACIBWHRnEAugyFHKE=
</data>
<key>Headers/IQAppStatus.h</key>
<data>
WnybOSMMVqCKGns0rEz9C3EfQOg=
</data>
<key>Headers/IQConstants.h</key>
<data>
eI7keKSkaajUZACnuMhgtV1RuBA=
</data>
<key>Headers/IQDevice.h</key>
<data>
bl545C/cu0mw2KlRmzojKmHPom0=
</data>
<key>Info.plist</key>
<data>
sMY09qXRBL/m1OGNWejLjfNg04w=
</data>
<key>Modules/module.modulemap</key>
<data>
SSRVAtIAdFmowQqE4HzOpWYLubg=
</data>
<key>ar.lproj/IQLocalizable.strings</key>
<dict>
<key>hash</key>
<data>
1CDTE/Qaf1Z/HuhSt9CUnwitv4M=
</data>
<key>optional</key>
<true/>
</dict>
<key>cs.lproj/IQLocalizable.strings</key>
<dict>
<key>hash</key>
<data>
/jkyQ77G2Xd9wy6QptBphGNbtCY=
</data>
<key>optional</key>
<true/>
</dict>
<key>da.lproj/IQLocalizable.strings</key>
<dict>
<key>hash</key>
<data>
FYi0wjOu/Hw//Qe96yqxSb9yClc=
</data>
<key>optional</key>
<true/>
</dict>
<key>de.lproj/IQLocalizable.strings</key>
<dict>
<key>hash</key>
<data>
MitzVbGhXhTLjPvw9vuWcQQa50Q=
</data>
<key>optional</key>
<true/>
</dict>
<key>el.lproj/IQLocalizable.strings</key>
<dict>
<key>hash</key>
<data>
n82gLcjjjHszaroTFeJUvSrrc0o=
</data>
<key>optional</key>
<true/>
</dict>
<key>en.lproj/IQLocalizable.strings</key>
<dict>
<key>hash</key>
<data>
hcxxLyrTI+aElXlPc5dwr7jdqwc=
</data>
<key>optional</key>
<true/>
</dict>
<key>es.lproj/IQLocalizable.strings</key>
<dict>
<key>hash</key>
<data>
ff8DVQtNhO8pF7HFnXjh8foHXbo=
</data>
<key>optional</key>
<true/>
</dict>
<key>fi.lproj/IQLocalizable.strings</key>
<dict>
<key>hash</key>
<data>
R9cr8yqJmu91Xz31tGyprGR3t/s=
</data>
<key>optional</key>
<true/>
</dict>
<key>fr.lproj/IQLocalizable.strings</key>
<dict>
<key>hash</key>
<data>
PwFmqFeRTcjdHmkXYrPzNVYoe5o=
</data>
<key>optional</key>
<true/>
</dict>
<key>he.lproj/IQLocalizable.strings</key>
<dict>
<key>hash</key>
<data>
/jPUgFtYbbyELG5DZ3Sjoi/If9w=
</data>
<key>optional</key>
<true/>
</dict>
<key>hr.lproj/IQLocalizable.strings</key>
<dict>
<key>hash</key>
<data>
H2GtdTeORRPCnogvpWY69Dg9uME=
</data>
<key>optional</key>
<true/>
</dict>
<key>hu.lproj/IQLocalizable.strings</key>
<dict>
<key>hash</key>
<data>
QIimMhNyYmqp4ZW01hfj554WAMg=
</data>
<key>optional</key>
<true/>
</dict>
<key>id.lproj/IQLocalizable.strings</key>
<dict>
<key>hash</key>
<data>
2/54a0gkcVuk1I3m4ulDAXOLL5o=
</data>
<key>optional</key>
<true/>
</dict>
<key>it.lproj/IQLocalizable.strings</key>
<dict>
<key>hash</key>
<data>
hNIKYIcP/87e6g7AUP+zKRtJ52M=
</data>
<key>optional</key>
<true/>
</dict>
<key>ja.lproj/IQLocalizable.strings</key>
<dict>
<key>hash</key>
<data>
0iU2PbJ/3xgXMZ20ffsqaWpxKWc=
</data>
<key>optional</key>
<true/>
</dict>
<key>ko.lproj/IQLocalizable.strings</key>
<dict>
<key>hash</key>
<data>
ERH8oHR9H9jMHjP0EAgaTtVhnX4=
</data>
<key>optional</key>
<true/>
</dict>
<key>ms.lproj/IQLocalizable.strings</key>
<dict>
<key>hash</key>
<data>
DkbQA2+v/qSgQWma/fg3647Bkqs=
</data>
<key>optional</key>
<true/>
</dict>
<key>nb.lproj/IQLocalizable.strings</key>
<dict>
<key>hash</key>
<data>
T3zFOvuvrJt5Vnmfqt2Mf/du8as=
</data>
<key>optional</key>
<true/>
</dict>
<key>nl.lproj/IQLocalizable.strings</key>
<dict>
<key>hash</key>
<data>
t9PD5JEbfoSLaQ7f8M2cLghOReI=
</data>
<key>optional</key>
<true/>
</dict>
<key>pl.lproj/IQLocalizable.strings</key>
<dict>
<key>hash</key>
<data>
wfTnhBccAm6JfwH/JkZKNRKTUAU=
</data>
<key>optional</key>
<true/>
</dict>
<key>pt-PT.lproj/IQLocalizable.strings</key>
<dict>
<key>hash</key>
<data>
7yXkcZEpJ4UiRHAzhK+vw/Q857Y=
</data>
<key>optional</key>
<true/>
</dict>
<key>pt.lproj/IQLocalizable.strings</key>
<dict>
<key>hash</key>
<data>
tZPncsQs8weCDJa03AKLpijXSUw=
</data>
<key>optional</key>
<true/>
</dict>
<key>ru.lproj/IQLocalizable.strings</key>
<dict>
<key>hash</key>
<data>
Ct+byJ3rWeigvg0q6rB/kQaR+yE=
</data>
<key>optional</key>
<true/>
</dict>
<key>sk.lproj/IQLocalizable.strings</key>
<dict>
<key>hash</key>
<data>
1yTM1nAsAYpSH7NrYU6/nFlqk5E=
</data>
<key>optional</key>
<true/>
</dict>
<key>sv.lproj/IQLocalizable.strings</key>
<dict>
<key>hash</key>
<data>
i84z6vuHLrFpO0qZ2V0zYjixIws=
</data>
<key>optional</key>
<true/>
</dict>
<key>th.lproj/IQLocalizable.strings</key>
<dict>
<key>hash</key>
<data>
oW5npy+pDJM1wUOgTkw9FY1Ave4=
</data>
<key>optional</key>
<true/>
</dict>
<key>tr.lproj/IQLocalizable.strings</key>
<dict>
<key>hash</key>
<data>
76rD7PLrQMiT5YTlI8IjEFgsiU4=
</data>
<key>optional</key>
<true/>
</dict>
<key>zh-Hans.lproj/IQLocalizable.strings</key>
<dict>
<key>hash</key>
<data>
DNlMxUKypOvKArzi7ioJUiFfFXg=
</data>
<key>optional</key>
<true/>
</dict>
<key>zh-Hant.lproj/IQLocalizable.strings</key>
<dict>
<key>hash</key>
<data>
U6I+uL07KIv2b77w0c0glaJlhMg=
</data>
<key>optional</key>
<true/>
</dict>
</dict>
<key>files2</key>
<dict>
<key>Headers/ConnectIQ.h</key>
<dict>
<key>hash</key>
<data>
F1hICh90Ex4ADEjYLcSi0YPhrPA=
</data>
<key>hash2</key>
<data>
ABtgvHbvmly4QpZO/KmmrwYkL0N+AqV3gXdPVrseysY=
</data>
</dict>
<key>Headers/IQApp.h</key>
<dict>
<key>hash</key>
<data>
R7+SmeArgBACIBWHRnEAugyFHKE=
</data>
<key>hash2</key>
<data>
X4vXt0sO9gxQNzQalIaLqMpSGNRC9ue2USDcfjBYkec=
</data>
</dict>
<key>Headers/IQAppStatus.h</key>
<dict>
<key>hash</key>
<data>
WnybOSMMVqCKGns0rEz9C3EfQOg=
</data>
<key>hash2</key>
<data>
tg9qNXtTmFUvNoJtq7O/aEXBNngcGENVRhvxLJ8C/xo=
</data>
</dict>
<key>Headers/IQConstants.h</key>
<dict>
<key>hash</key>
<data>
eI7keKSkaajUZACnuMhgtV1RuBA=
</data>
<key>hash2</key>
<data>
bqDpm8yikc2FIqaSUHcLqPY6TPXLlXSUo+Dl9NUYwmA=
</data>
</dict>
<key>Headers/IQDevice.h</key>
<dict>
<key>hash</key>
<data>
bl545C/cu0mw2KlRmzojKmHPom0=
</data>
<key>hash2</key>
<data>
4N4+64IHeb9iBwyziNxo0SMuCM75ez9Em4UfmtgtTHA=
</data>
</dict>
<key>Modules/module.modulemap</key>
<dict>
<key>hash</key>
<data>
SSRVAtIAdFmowQqE4HzOpWYLubg=
</data>
<key>hash2</key>
<data>
lQGjVO5Q0wfztjETCwDkwAkQ7nZInCgWdStnHL3o6Co=
</data>
</dict>
<key>ar.lproj/IQLocalizable.strings</key>
<dict>
<key>hash</key>
<data>
1CDTE/Qaf1Z/HuhSt9CUnwitv4M=
</data>
<key>hash2</key>
<data>
CWyQue2TCS0heGoGbN4ffetM2QZSk7lqgc2Wer2fgTg=
</data>
<key>optional</key>
<true/>
</dict>
<key>cs.lproj/IQLocalizable.strings</key>
<dict>
<key>hash</key>
<data>
/jkyQ77G2Xd9wy6QptBphGNbtCY=
</data>
<key>hash2</key>
<data>
1mSn+EYeYcTV1dArgHz7PkmZrV6mHWfnuG5aDa6Y87E=
</data>
<key>optional</key>
<true/>
</dict>
<key>da.lproj/IQLocalizable.strings</key>
<dict>
<key>hash</key>
<data>
FYi0wjOu/Hw//Qe96yqxSb9yClc=
</data>
<key>hash2</key>
<data>
yLkvGzd+smkOjicvW/+Oe6wGGyirHS+/YfjuSzyVoMM=
</data>
<key>optional</key>
<true/>
</dict>
<key>de.lproj/IQLocalizable.strings</key>
<dict>
<key>hash</key>
<data>
MitzVbGhXhTLjPvw9vuWcQQa50Q=
</data>
<key>hash2</key>
<data>
DFHv7MWBJmyAkOj993NmSFKbS2t8/vtSev603sBUtjI=
</data>
<key>optional</key>
<true/>
</dict>
<key>el.lproj/IQLocalizable.strings</key>
<dict>
<key>hash</key>
<data>
n82gLcjjjHszaroTFeJUvSrrc0o=
</data>
<key>hash2</key>
<data>
i4FAK4mi+SgS6oZv8zM74kRZToakn49E8GD7FcJBLoQ=
</data>
<key>optional</key>
<true/>
</dict>
<key>en.lproj/IQLocalizable.strings</key>
<dict>
<key>hash</key>
<data>
hcxxLyrTI+aElXlPc5dwr7jdqwc=
</data>
<key>hash2</key>
<data>
vmBi9DFJzFcG0OwaWKSDjgklNi407U8u2pz3EnEENN4=
</data>
<key>optional</key>
<true/>
</dict>
<key>es.lproj/IQLocalizable.strings</key>
<dict>
<key>hash</key>
<data>
ff8DVQtNhO8pF7HFnXjh8foHXbo=
</data>
<key>hash2</key>
<data>
z6RjynaWjrRKHmv4sLirc4eXwKOtQdylzj5+TiHpaTc=
</data>
<key>optional</key>
<true/>
</dict>
<key>fi.lproj/IQLocalizable.strings</key>
<dict>
<key>hash</key>
<data>
R9cr8yqJmu91Xz31tGyprGR3t/s=
</data>
<key>hash2</key>
<data>
6BI0iPRVWaP63/XFdjLBz6z7DsvvuOoaEAS+mYzrx8E=
</data>
<key>optional</key>
<true/>
</dict>
<key>fr.lproj/IQLocalizable.strings</key>
<dict>
<key>hash</key>
<data>
PwFmqFeRTcjdHmkXYrPzNVYoe5o=
</data>
<key>hash2</key>
<data>
geXjZzXre2CRiALecPFBGz4JSJA7MbkDnB4qrEMKNwk=
</data>
<key>optional</key>
<true/>
</dict>
<key>he.lproj/IQLocalizable.strings</key>
<dict>
<key>hash</key>
<data>
/jPUgFtYbbyELG5DZ3Sjoi/If9w=
</data>
<key>hash2</key>
<data>
47mcrSx16SFjWPIiN7guCAG0va8NiJ6I5s45tSVEHlY=
</data>
<key>optional</key>
<true/>
</dict>
<key>hr.lproj/IQLocalizable.strings</key>
<dict>
<key>hash</key>
<data>
H2GtdTeORRPCnogvpWY69Dg9uME=
</data>
<key>hash2</key>
<data>
4bQvygPax6VBpoFlyS5by1N6otnDMliHu+bWsDaWSQc=
</data>
<key>optional</key>
<true/>
</dict>
<key>hu.lproj/IQLocalizable.strings</key>
<dict>
<key>hash</key>
<data>
QIimMhNyYmqp4ZW01hfj554WAMg=
</data>
<key>hash2</key>
<data>
0m2fIyz26vh3RlUqqSXvoNTLovxIixrUyJoL/IDSoVk=
</data>
<key>optional</key>
<true/>
</dict>
<key>id.lproj/IQLocalizable.strings</key>
<dict>
<key>hash</key>
<data>
2/54a0gkcVuk1I3m4ulDAXOLL5o=
</data>
<key>hash2</key>
<data>
hQf9SrG7d8aVWsXIbCIxkKEJjbnW1FLvS+MbOI1VtHQ=
</data>
<key>optional</key>
<true/>
</dict>
<key>it.lproj/IQLocalizable.strings</key>
<dict>
<key>hash</key>
<data>
hNIKYIcP/87e6g7AUP+zKRtJ52M=
</data>
<key>hash2</key>
<data>
XAbEWX6cicDxGzxGgSx3DhF4rjUHX4LV+dO0X3rUEqc=
</data>
<key>optional</key>
<true/>
</dict>
<key>ja.lproj/IQLocalizable.strings</key>
<dict>
<key>hash</key>
<data>
0iU2PbJ/3xgXMZ20ffsqaWpxKWc=
</data>
<key>hash2</key>
<data>
YOqOvZq0WEN4DCoSwc0lcTSRc4C812DqzjIsaid1SHg=
</data>
<key>optional</key>
<true/>
</dict>
<key>ko.lproj/IQLocalizable.strings</key>
<dict>
<key>hash</key>
<data>
ERH8oHR9H9jMHjP0EAgaTtVhnX4=
</data>
<key>hash2</key>
<data>
WJyaRCWn1KqmcDeajRnC41MdNrlpbI+1JbPkXhbKrKY=
</data>
<key>optional</key>
<true/>
</dict>
<key>ms.lproj/IQLocalizable.strings</key>
<dict>
<key>hash</key>
<data>
DkbQA2+v/qSgQWma/fg3647Bkqs=
</data>
<key>hash2</key>
<data>
gztYxa4Hn58HkKmcUIZI1jCz44IETZeMsqrpZSKxJvc=
</data>
<key>optional</key>
<true/>
</dict>
<key>nb.lproj/IQLocalizable.strings</key>
<dict>
<key>hash</key>
<data>
T3zFOvuvrJt5Vnmfqt2Mf/du8as=
</data>
<key>hash2</key>
<data>
Oy6UOwSN+/xPIrthAEvzV8PEn27kfsHpMMLU5w1rww0=
</data>
<key>optional</key>
<true/>
</dict>
<key>nl.lproj/IQLocalizable.strings</key>
<dict>
<key>hash</key>
<data>
t9PD5JEbfoSLaQ7f8M2cLghOReI=
</data>
<key>hash2</key>
<data>
XbijhSaZgmsW59Vo9ZEbhDuUQH18fHizWKzsLosiM0o=
</data>
<key>optional</key>
<true/>
</dict>
<key>pl.lproj/IQLocalizable.strings</key>
<dict>
<key>hash</key>
<data>
wfTnhBccAm6JfwH/JkZKNRKTUAU=
</data>
<key>hash2</key>
<data>
MQYgqA+Hl03JJ261Q19K5Lt64kSTBP+pfpD+jOVE3AU=
</data>
<key>optional</key>
<true/>
</dict>
<key>pt-PT.lproj/IQLocalizable.strings</key>
<dict>
<key>hash</key>
<data>
7yXkcZEpJ4UiRHAzhK+vw/Q857Y=
</data>
<key>hash2</key>
<data>
seINq3QazVameLGOW+pIAtGWLa6NDl5XWRtqnObxywo=
</data>
<key>optional</key>
<true/>
</dict>
<key>pt.lproj/IQLocalizable.strings</key>
<dict>
<key>hash</key>
<data>
tZPncsQs8weCDJa03AKLpijXSUw=
</data>
<key>hash2</key>
<data>
GnzdqEuQwORzVCih99bwr79UHIyzXm+zuN5b9m1NrKY=
</data>
<key>optional</key>
<true/>
</dict>
<key>ru.lproj/IQLocalizable.strings</key>
<dict>
<key>hash</key>
<data>
Ct+byJ3rWeigvg0q6rB/kQaR+yE=
</data>
<key>hash2</key>
<data>
yCN9s/JXYqsMNZ1icaH4hUwyMQ1NtxOmV6sIAtRd9pc=
</data>
<key>optional</key>
<true/>
</dict>
<key>sk.lproj/IQLocalizable.strings</key>
<dict>
<key>hash</key>
<data>
1yTM1nAsAYpSH7NrYU6/nFlqk5E=
</data>
<key>hash2</key>
<data>
OFHDtkGLLSfTuSx8GOTycKDCKOKmX0Wh2QG1CHhRz3I=
</data>
<key>optional</key>
<true/>
</dict>
<key>sv.lproj/IQLocalizable.strings</key>
<dict>
<key>hash</key>
<data>
i84z6vuHLrFpO0qZ2V0zYjixIws=
</data>
<key>hash2</key>
<data>
a3Gk+3USOT5uundOXrNCgnbcD0rDo2lkCO7b7+zg2Is=
</data>
<key>optional</key>
<true/>
</dict>
<key>th.lproj/IQLocalizable.strings</key>
<dict>
<key>hash</key>
<data>
oW5npy+pDJM1wUOgTkw9FY1Ave4=
</data>
<key>hash2</key>
<data>
qxGqAqRMwm0/dMd0W7DUsvbWb9x65GT+3d1zOQEql1w=
</data>
<key>optional</key>
<true/>
</dict>
<key>tr.lproj/IQLocalizable.strings</key>
<dict>
<key>hash</key>
<data>
76rD7PLrQMiT5YTlI8IjEFgsiU4=
</data>
<key>hash2</key>
<data>
Y6TnKQmqO/TAx+0KYqRRG6UOz7I/gM1YmbUwgSfZSQU=
</data>
<key>optional</key>
<true/>
</dict>
<key>zh-Hans.lproj/IQLocalizable.strings</key>
<dict>
<key>hash</key>
<data>
DNlMxUKypOvKArzi7ioJUiFfFXg=
</data>
<key>hash2</key>
<data>
BI3m4MTMHuPI4sQKPGeQnxIlBJJrXwgVuR7Ho1Q5o6Y=
</data>
<key>optional</key>
<true/>
</dict>
<key>zh-Hant.lproj/IQLocalizable.strings</key>
<dict>
<key>hash</key>
<data>
U6I+uL07KIv2b77w0c0glaJlhMg=
</data>
<key>hash2</key>
<data>
14dQnjX3pEz2Um4J/fOdQDRe/LSuXxqkg1hEkO8E5ys=
</data>
<key>optional</key>
<true/>
</dict>
</dict>
<key>rules</key>
<dict>
<key>^.*</key>
<true/>
<key>^.*\.lproj/</key>
<dict>
<key>optional</key>
<true/>
<key>weight</key>
<real>1000</real>
</dict>
<key>^.*\.lproj/locversion.plist$</key>
<dict>
<key>omit</key>
<true/>
<key>weight</key>
<real>1100</real>
</dict>
<key>^Base\.lproj/</key>
<dict>
<key>weight</key>
<real>1010</real>
</dict>
<key>^version.plist$</key>
<true/>
</dict>
<key>rules2</key>
<dict>
<key>.*\.dSYM($|/)</key>
<dict>
<key>weight</key>
<real>11</real>
</dict>
<key>^(.*/)?\.DS_Store$</key>
<dict>
<key>omit</key>
<true/>
<key>weight</key>
<real>2000</real>
</dict>
<key>^.*</key>
<true/>
<key>^.*\.lproj/</key>
<dict>
<key>optional</key>
<true/>
<key>weight</key>
<real>1000</real>
</dict>
<key>^.*\.lproj/locversion.plist$</key>
<dict>
<key>omit</key>
<true/>
<key>weight</key>
<real>1100</real>
</dict>
<key>^Base\.lproj/</key>
<dict>
<key>weight</key>
<real>1010</real>
</dict>
<key>^Info\.plist$</key>
<dict>
<key>omit</key>
<true/>
<key>weight</key>
<real>20</real>
</dict>
<key>^PkgInfo$</key>
<dict>
<key>omit</key>
<true/>
<key>weight</key>
<real>20</real>
</dict>
<key>^embedded\.provisionprofile$</key>
<dict>
<key>weight</key>
<real>20</real>
</dict>
<key>^version\.plist$</key>
<dict>
<key>weight</key>
<real>20</real>
</dict>
</dict>
</dict>
</plist>

View File

@@ -9,6 +9,12 @@ import QtMultimedia 5.15
HomeForm{
objectName: "home"
background: Rectangle {
anchors.fill: parent
width: parent.fill
height: parent.fill
color: settings.theme_background_color
}
signal start_clicked;
signal stop_clicked;
signal lap_clicked;
@@ -21,6 +27,12 @@ HomeForm{
Settings {
id: settings
property real ui_zoom: 100.0
property bool theme_tile_icon_enabled: true
property string theme_tile_background_color: "#303030"
property string theme_background_color: "#303030"
property bool theme_tile_shadow_enabled: true
property string theme_tile_shadow_color: "#9C27B0"
property int theme_tile_secondline_textsize: 12
}
MessageDialog {
@@ -154,26 +166,27 @@ HomeForm{
height: 123 * settings.ui_zoom / 100
radius: 3
border.width: 1
border.color: "purple"
color: Material.backgroundColor
border.color: (settings.theme_tile_shadow_enabled ? settings.theme_tile_shadow_color : settings.theme_tile_background_color)
color: settings.theme_tile_background_color
id: rect
}
DropShadow {
visible: settings.theme_tile_shadow_enabled
anchors.fill: rect
cached: true
horizontalOffset: 3
verticalOffset: 3
radius: 8.0
samples: 16
color: Material.color(Material.Purple)
color: settings.theme_tile_shadow_color
source: rect
}
Timer {
id: toggleIconTimer
interval: 500; running: true; repeat: true
onTriggered: { if(identificator === "inclination" && rootItem.autoInclinationEnabled()) myIcon.visible = !myIcon.visible; else myIcon.visible = true; }
onTriggered: { if(identificator === "inclination" && rootItem.autoInclinationEnabled()) myIcon.visible = !myIcon.visible; else myIcon.visible = settings.theme_tile_icon_enabled && !largeButton; }
}
Image {
@@ -185,7 +198,7 @@ HomeForm{
width: 48 * settings.ui_zoom / 100
height: 48 * settings.ui_zoom / 100
source: icon
visible: !largeButton
visible: settings.theme_tile_icon_enabled && !largeButton
}
Text {
objectName: "value"
@@ -212,7 +225,7 @@ HomeForm{
}
text: secondLine
horizontalAlignment: Text.AlignHCenter
font.pointSize: 12 * settings.ui_zoom / 100
font.pointSize: settings.theme_tile_secondline_textsize * settings.ui_zoom / 100
font.bold: false
visible: !largeButton
}
@@ -284,7 +297,8 @@ HomeForm{
anchors.top: gridView.bottom
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
@@ -292,6 +306,7 @@ HomeForm{
videoPlaybackHalf.play() :
videoPlaybackHalf.pause()) } }
}
*/
onVisibleChanged: {
if(visible === true) {
@@ -302,7 +317,7 @@ HomeForm{
videoPlaybackHalf.seek(rootItem.videoPosition)
videoPlaybackHalf.play()
videoPlaybackHalf.muted = true
videoPlaybackHalf.muted = rootItem.currentCoordinateValid
} else {
videoPlaybackHalf.stop()
}

View File

@@ -2,6 +2,7 @@ import QtQuick 2.12
import QtQuick.Controls 2.5
import QtQuick.Controls.Material 2.12
import QtGraphicalEffects 1.12
import Qt.labs.settings 1.0
Page {
@@ -13,6 +14,13 @@ Page {
property alias lap: lap
property alias row: row
Settings {
id: settings
property real ui_zoom: 100.0
property bool theme_tile_icon_enabled: true
property string theme_background_color: "#303030"
}
Item {
width: parent.width
height: rootItem.topBarHeight
@@ -30,7 +38,7 @@ Page {
Rectangle {
width: 50
height: row.height
color: Material.backgroundColor
color: settings.theme_background_color
Column {
id: column
anchors.horizontalCenter: parent.horizontalCenter
@@ -42,7 +50,7 @@ Page {
Rectangle {
width: 50
height: row.height
color: Material.backgroundColor
color: settings.theme_background_color
Image {
anchors.verticalCenter: parent.verticalCenter
@@ -73,7 +81,7 @@ Page {
Rectangle {
width: 120
height: row.height
color: Material.backgroundColor
color: settings.theme_background_color
RoundButton {
icon.source: rootItem.startIcon
icon.height: row.height - 54
@@ -95,7 +103,7 @@ Page {
Rectangle {
width: 120
height: row.height
color: Material.backgroundColor
color: settings.theme_background_color
RoundButton {
icon.source: rootItem.stopIcon
@@ -119,7 +127,7 @@ Page {
id: item2
width: 50
height: row.height
color: Material.backgroundColor
color: settings.theme_background_color
RoundButton {
anchors.verticalCenter: parent.verticalCenter
id: lap

View File

@@ -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();
}
}*/
}
}

96
src/Toast.qml Normal file
View File

@@ -0,0 +1,96 @@
import QtQuick 2.0
/**
* adapted from StackOverflow:
* http://stackoverflow.com/questions/26879266/make-toast-in-android-by-qml
*/
/**
* @brief An Android-like timed message text in a box that self-destroys when finished if desired
*/
Rectangle {
/**
* Public
*/
/**
* @brief Shows this Toast
*
* @param {string} text Text to show
* @param {real} duration Duration to show in milliseconds, defaults to 3000
*/
function show(text, duration) {
message.text = text;
if (typeof duration !== "undefined") { // checks if parameter was passed
time = Math.max(duration, 2 * fadeTime);
}
else {
time = defaultTime;
}
animation.start();
}
/**
* Private
*/
id: root
readonly property real defaultTime: 3000
property real time: defaultTime
readonly property real fadeTime: 300
property real margin: 10
anchors {
left: (parent != null) ? parent.left : undefined
right: (parent != null) ? parent.right : undefined
margins: margin
}
height: message.height + margin
radius: margin
opacity: 0
color: "#222222"
Text {
id: message
color: "white"
wrapMode: Text.Wrap
horizontalAlignment: Text.AlignHCenter
anchors {
top: parent.top
left: parent.left
right: parent.right
margins: margin / 2
}
}
SequentialAnimation on opacity {
id: animation
running: false
NumberAnimation {
to: .9
duration: fadeTime
}
PauseAnimation {
duration: time - 2 * fadeTime
}
NumberAnimation {
to: 0
duration: fadeTime
}
onRunningChanged: {
if (!running) {
+ toastManager.model.remove(index);
}
}
}
}

56
src/ToastManager.qml Normal file
View File

@@ -0,0 +1,56 @@
import QtQuick 2.0
/**
* adapted from StackOverflow:
* http://stackoverflow.com/questions/26879266/make-toast-in-android-by-qml
* @brief Manager that creates Toasts dynamically
*/
ListView {
/**
* Public
*/
/**
* @brief Shows a Toast
*
* @param {string} text Text to show
* @param {real} duration Duration to show in milliseconds, defaults to 3000
*/
function show(text, duration) {
model.insert(0, {text: text, duration: duration});
}
/**
* Private
*/
id: root
z: Infinity
spacing: 5
anchors.fill: parent
anchors.bottomMargin: 10
verticalLayoutDirection: ListView.BottomToTop
interactive: false
displaced: Transition {
NumberAnimation {
properties: "y"
easing.type: Easing.InOutQuad
}
}
delegate: Toast {
Component.onCompleted: {
if (typeof duration === "undefined") {
show(text);
}
else {
show(text, duration);
}
}
}
model: ListModel {id: model}
}

View File

@@ -102,9 +102,9 @@ ColumnLayout {
clip: true
Text {
id: fileTextBox
color: (!folderModel.isFolder(index)?Material.color(Material.Grey):Material.color(Material.Orange))
color: (!folderModel.isFolder(index)?Material.color(Material.Grey):Material.color(Material.Orange))
font.pixelSize: Qt.application.font.pixelSize * 1.6
text: fileName.substring(0, fileName.length-4)
text: (!folderModel.isFolder(index)?fileName.substring(0, fileName.length-4):fileName)
NumberAnimation on x {
Component.onCompleted: {
if(fileName.length > 30) {

View File

@@ -1,7 +1,9 @@
#include "activiotreadmill.h"
#include "virtualbike.h"
#include "ios/lockscreen.h"
#ifdef Q_OS_ANDROID
#include "keepawakehelper.h"
#endif
#include "virtualtreadmill.h"
#include <QBluetoothLocalDevice>
#include <QDateTime>
@@ -54,10 +56,15 @@ void activiotreadmill::writeCharacteristic(const QLowEnergyCharacteristic charac
return;
}
gattCommunicationChannelService->writeCharacteristic(characteristic, QByteArray((const char *)data, data_len));
if (writeBuffer) {
delete writeBuffer;
}
writeBuffer = new QByteArray((const char *)data, data_len);
gattCommunicationChannelService->writeCharacteristic(characteristic, *writeBuffer);
if (!disable_log) {
emit debug(QStringLiteral(" >> ") + QByteArray((const char *)data, data_len).toHex(' ') +
emit debug(QStringLiteral(" >> ") + writeBuffer->toHex(' ') +
QStringLiteral(" // ") + info);
}
@@ -74,59 +81,59 @@ void activiotreadmill::forceSpeed(double requestSpeed) {
writeSpeed[1] = (requestSpeed * 10);
writeSpeed[5] += writeSpeed[1];
if(!settings.value(QZSettings::fitfiu_mc_v460, QZSettings::default_fitfiu_mc_v460).toBool())
if (!settings.value(QZSettings::fitfiu_mc_v460, QZSettings::default_fitfiu_mc_v460).toBool() &&
!settings.value(QZSettings::zero_zt2500_treadmill, QZSettings::default_zero_zt2500_treadmill).toBool())
writeSpeed[6] = writeSpeed[1] + 1;
else {
switch(writeSpeed[1] & 0x0F) {
case 0x00:
writeSpeed[6] = writeSpeed[1] + 5;
break;
case 0x01:
writeSpeed[6] = writeSpeed[1] + 3;
break;
case 0x02:
writeSpeed[6] = writeSpeed[1] + 1;
break;
case 0x03:
writeSpeed[6] = writeSpeed[1] - 1;
break;
case 0x04:
writeSpeed[6] = writeSpeed[1] + 5;
break;
case 0x05:
writeSpeed[6] = writeSpeed[1] + 3;
break;
case 0x06:
writeSpeed[6] = writeSpeed[1] + 1;
break;
case 0x07:
writeSpeed[6] = writeSpeed[1] - 1;
break;
case 0x08:
writeSpeed[6] = writeSpeed[1] + 5;
break;
case 0x09:
writeSpeed[6] = writeSpeed[1] + 3;
break;
case 0x0A:
writeSpeed[6] = writeSpeed[1] + 1;
break;
case 0x0B:
writeSpeed[6] = writeSpeed[1] - 1;
break;
case 0x0C:
writeSpeed[6] = writeSpeed[1] + 5;
break;
case 0x0D:
writeSpeed[6] = writeSpeed[1] + 3;
break;
case 0x0E:
writeSpeed[6] = writeSpeed[1] + 1;
break;
case 0x0F:
writeSpeed[6] = writeSpeed[1] - 1;
break;
switch (writeSpeed[1] & 0x0F) {
case 0x00:
writeSpeed[6] = writeSpeed[1] + 5;
break;
case 0x01:
writeSpeed[6] = writeSpeed[1] + 3;
break;
case 0x02:
writeSpeed[6] = writeSpeed[1] + 1;
break;
case 0x03:
writeSpeed[6] = writeSpeed[1] - 1;
break;
case 0x04:
writeSpeed[6] = writeSpeed[1] + 5;
break;
case 0x05:
writeSpeed[6] = writeSpeed[1] + 3;
break;
case 0x06:
writeSpeed[6] = writeSpeed[1] + 1;
break;
case 0x07:
writeSpeed[6] = writeSpeed[1] - 1;
break;
case 0x08:
writeSpeed[6] = writeSpeed[1] + 5;
break;
case 0x09:
writeSpeed[6] = writeSpeed[1] + 3;
break;
case 0x0A:
writeSpeed[6] = writeSpeed[1] + 1;
break;
case 0x0B:
writeSpeed[6] = writeSpeed[1] - 1;
break;
case 0x0C:
writeSpeed[6] = writeSpeed[1] + 5;
break;
case 0x0D:
writeSpeed[6] = writeSpeed[1] + 3;
break;
case 0x0E:
writeSpeed[6] = writeSpeed[1] + 1;
break;
case 0x0F:
writeSpeed[6] = writeSpeed[1] - 1;
break;
}
}
@@ -167,21 +174,26 @@ void activiotreadmill::update() {
QSettings settings;
// ******************************************* virtual treadmill init *************************************
if (!firstInit && !virtualTreadMill && !virtualBike) {
bool virtual_device_enabled = settings.value(QZSettings::virtual_device_enabled, QZSettings::default_virtual_device_enabled).toBool();
bool virtual_device_force_bike = settings.value(QZSettings::virtual_device_force_bike, QZSettings::default_virtual_device_force_bike).toBool();
if (!firstInit && !this->hasVirtualDevice()) {
bool virtual_device_enabled =
settings.value(QZSettings::virtual_device_enabled, QZSettings::default_virtual_device_enabled).toBool();
bool virtual_device_force_bike =
settings.value(QZSettings::virtual_device_force_bike, QZSettings::default_virtual_device_force_bike)
.toBool();
if (virtual_device_enabled) {
if (!virtual_device_force_bike) {
debug("creating virtual treadmill interface...");
virtualTreadMill = new virtualtreadmill(this, noHeartService);
auto virtualTreadMill = new virtualtreadmill(this, noHeartService);
connect(virtualTreadMill, &virtualtreadmill::debug, this, &activiotreadmill::debug);
connect(virtualTreadMill, &virtualtreadmill::changeInclination, this,
&activiotreadmill::changeInclinationRequested);
this->setVirtualDevice(virtualTreadMill, VIRTUAL_DEVICE_MODE::PRIMARY);
} else {
debug("creating virtual bike interface...");
virtualBike = new virtualbike(this);
auto virtualBike = new virtualbike(this);
connect(virtualBike, &virtualbike::changeInclination, this,
&activiotreadmill::changeInclinationRequested);
this->setVirtualDevice(virtualBike, VIRTUAL_DEVICE_MODE::ALTERNATIVE);
}
firstInit = 1;
}
@@ -201,7 +213,7 @@ void activiotreadmill::update() {
requestSpeed = -1;
}
if (requestInclination != -100) {
if(requestInclination < 0)
if (requestInclination < 0)
requestInclination = 0;
if (requestInclination != currentInclination().value() && requestInclination >= 0 &&
requestInclination <= 15) {
@@ -297,10 +309,10 @@ void activiotreadmill::characteristicChanged(const QLowEnergyCharacteristic &cha
double speed = GetSpeedFromPacket(value);
double incline = 1.0; // "fitfiu_mc_v460" has 1.0 fixed inclination
if(!settings.value(QZSettings::fitfiu_mc_v460, QZSettings::default_fitfiu_mc_v460).toBool())
if (!settings.value(QZSettings::fitfiu_mc_v460, QZSettings::default_fitfiu_mc_v460).toBool())
incline = GetInclinationFromPacket(value);
// double kcal = GetKcalFromPacket(value);
// double distance = GetDistanceFromPacket(value);
// double kcal = GetKcalFromPacket(value);
// double distance = GetDistanceFromPacket(value);
#ifdef Q_OS_ANDROID
if (settings.value(QZSettings::ant_heart, QZSettings::default_ant_heart).toBool())
@@ -312,17 +324,7 @@ void activiotreadmill::characteristicChanged(const QLowEnergyCharacteristic &cha
uint8_t heart = 0;
if (heart == 0) {
#ifdef Q_OS_IOS
#ifndef IO_UNDER_QT
lockscreen h;
long appleWatchHeartRate = h.heartRate();
h.setKcal(KCal.value());
h.setDistance(Distance.value());
Heart = appleWatchHeartRate;
debug("Current Heart from Apple Watch: " + QString::number(appleWatchHeartRate));
#endif
#endif
update_hr_from_external();
} else
Heart = heart;
@@ -332,7 +334,8 @@ void activiotreadmill::characteristicChanged(const QLowEnergyCharacteristic &cha
if (!firstCharacteristicChanged) {
if (watts(settings.value(QZSettings::weight, QZSettings::default_weight).toFloat()))
KCal +=
((((0.048 * ((double)watts(settings.value(QZSettings::weight, QZSettings::default_weight).toFloat())) + 1.19) *
((((0.048 * ((double)watts(settings.value(QZSettings::weight, QZSettings::default_weight).toFloat())) +
1.19) *
settings.value(QZSettings::weight, QZSettings::default_weight).toFloat() * 3.5) /
200.0) /
(60000.0 / ((double)lastTimeCharacteristicChanged.msecsTo(
@@ -518,7 +521,9 @@ void activiotreadmill::btinit(bool startTape) {
uint8_t initData2[] = {0x01, 0x00, 0x00, 0x00, 0x00, 0x26, 0x03};
writeCharacteristic(gattWrite2Characteristic, initData1, sizeof(initData1), QStringLiteral("init"), false, false);
writeCharacteristic(gattWriteCharacteristic, initData2, sizeof(initData2), QStringLiteral("init"), false, true);
// starts the tape
// writeCharacteristic(gattWriteCharacteristic, initData2, sizeof(initData2), QStringLiteral("init"), false, true);
if (startTape) {
}
@@ -675,8 +680,4 @@ bool activiotreadmill::connected() {
return m_control->state() == QLowEnergyController::DiscoveredState;
}
void *activiotreadmill::VirtualTreadMill() { return virtualTreadMill; }
void *activiotreadmill::VirtualDevice() { return VirtualTreadMill(); }
void activiotreadmill::searchingStop() { searchStopped = true; }

View File

@@ -28,8 +28,6 @@
#include <QObject>
#include "treadmill.h"
#include "virtualbike.h"
#include "virtualtreadmill.h"
#ifdef Q_OS_IOS
#include "ios/lockscreen.h"
@@ -41,11 +39,8 @@ class activiotreadmill : public treadmill {
public:
activiotreadmill(uint32_t poolDeviceTime = 200, bool noConsole = false, bool noHeartService = false,
double forceInitSpeed = 0.0, double forceInitInclination = 0.0);
bool connected();
double minStepInclination();
void *VirtualTreadMill();
void *VirtualDevice();
bool connected() override;
double minStepInclination() override;
private:
double GetSpeedFromPacket(const QByteArray &packet);
@@ -67,8 +62,6 @@ class activiotreadmill : public treadmill {
bool firstCharacteristicChanged = true;
QTimer *refresh;
virtualtreadmill *virtualTreadMill = nullptr;
virtualbike *virtualBike = 0;
QLowEnergyService *gattCommunicationChannelService = nullptr;
QLowEnergyCharacteristic gattWriteCharacteristic;

View File

@@ -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.21" android:versionCode="526" 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.13.99" android:versionCode="615" 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 -->
@@ -15,6 +15,12 @@
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
</intent-filter>
<meta-data
android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
android:resource="@xml/device_filter" />
<!-- Application arguments -->
<!-- meta-data android:name="android.app.arguments" android:value="arg1 arg2 arg3"/ -->
<!-- Application arguments -->

View File

@@ -38,13 +38,13 @@ dependencies {
def appcompat_version = "1.3.1"
implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar'])
implementation "com.android.billingclient:billing:4.0.0"
implementation "com.android.billingclient:billing:5.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:3.4.6'
implementation 'com.github.mik3y:usb-serial-for-android:v3.4.6'
androidTestImplementation "com.android.support:support-annotations:28.0.0"
}
@@ -100,4 +100,24 @@ android {
minSdkVersion = 21
targetSdkVersion = 33
}
tasks.all { task ->
if (task.name == 'compileDebugJavaWithJavac' && amazon == "1") {
task.dependsOn copyArm64Directory
task.dependsOn copyArm32Directory
}
}
}
task copyArm64Directory(type: Copy) {
from "libs/arm64-v8a/"
include '*arm64-v8a.so'
into "libs/armeabi-v7a/"
}
task copyArm32Directory(type: Copy) {
from "libs/armeabi-v7a/"
include '*armeabi-v7a.so'
into "libs/arm64-v8a/"
}

Some files were not shown because too many files have changed in this diff Show More