mirror of
https://github.com/cagnulein/qdomyos-zwift.git
synced 2026-02-18 23:41:50 +01:00
Compare commits
41 Commits
ios_adb_th
...
opencv_and
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a57408229b | ||
|
|
82578e4923 | ||
|
|
4682c2b172 | ||
|
|
64eace5ab9 | ||
|
|
b39b98b0d8 | ||
|
|
86e02be26e | ||
|
|
b00e77a4ea | ||
|
|
f80a8f4051 | ||
|
|
f45d3b9914 | ||
|
|
bcb102e0dc | ||
|
|
acee1b1301 | ||
|
|
0f9e7c0829 | ||
|
|
efd22aaee2 | ||
|
|
944d6d5ef2 | ||
|
|
14fb0a5cde | ||
|
|
da6faf18b5 | ||
|
|
6c662b20de | ||
|
|
75030bd25a | ||
|
|
a8b36057ce | ||
|
|
01e94e752c | ||
|
|
d83bcf984d | ||
|
|
ca93611acc | ||
|
|
9868a80be6 | ||
|
|
0d0db9fe3d | ||
|
|
09affb4dd1 | ||
|
|
ba1afdfa5a | ||
|
|
8ce3ae8ebd | ||
|
|
6778364353 | ||
|
|
1d4fa21899 | ||
|
|
fa94706754 | ||
|
|
3c5dc35675 | ||
|
|
bc5a1161df | ||
|
|
7e5ff25d39 | ||
|
|
0e46b52c64 | ||
|
|
377381bb64 | ||
|
|
85558eda35 | ||
|
|
8132e56483 | ||
|
|
ab86534f31 | ||
|
|
ab92d03891 | ||
|
|
cb2980741e | ||
|
|
8304f43bc5 |
546
.github/workflows/main.yml
vendored
546
.github/workflows/main.yml
vendored
@@ -14,8 +14,8 @@ on:
|
||||
branches: [ master, github-workflow-playground ]
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
schedule:
|
||||
- cron: "0 0 * * *"
|
||||
# schedule:
|
||||
# - cron: "0 */12 * * *"
|
||||
|
||||
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
|
||||
jobs:
|
||||
@@ -70,20 +70,15 @@ jobs:
|
||||
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: 3.7
|
||||
python-version: 3.10.11
|
||||
- name: download python and paddleocr
|
||||
run: |
|
||||
python -VV
|
||||
python -m pip install --upgrade pip
|
||||
python -m pip install --upgrade setuptools
|
||||
python -m pip install "protobuf<=3.20.2,>=3.1.0"
|
||||
python -m pip install paddlepaddle==2.5.1
|
||||
python -m pip install paddleocr
|
||||
python -m pip install imutils
|
||||
python -m pip install "Pillow<10.0.0"
|
||||
python -m pip install opencv-python
|
||||
python -m pip install numpy
|
||||
python -m pip install pywin32
|
||||
python -m pip install paddlepaddle-gpu==2.4.2.post117 -f https://www.paddlepaddle.org.cn/whl/windows/mkl/avx/stable.html
|
||||
python -m pip install https://files.pythonhosted.org/packages/03/ac/13fbe0ebf110d57a89f055a292d4fe430fee3fb22c56f8c077e63e0c5a4e/paddlepaddle-2.4.2-cp310-cp310-win_amd64.whl
|
||||
python -m pip install paddleocr>=2.0.1
|
||||
if: matrix.config.python
|
||||
|
||||
- uses: msys2/setup-msys2@v2
|
||||
@@ -122,20 +117,15 @@ jobs:
|
||||
make install
|
||||
cd ../..
|
||||
|
||||
- name: Secrets
|
||||
if: github.ref == 'refs/heads/main'
|
||||
run: |
|
||||
cd src
|
||||
echo "#define STRAVA_SECRET_KEY ${{ secrets.strava_secret_key }}" > secret.h
|
||||
echo "#define SMTP_USERNAME ${{ secrets.smtp_username }}" >> secret.h
|
||||
echo "#define SMTP_PASSWORD ${{ secrets.smtp_password }}" >> secret.h
|
||||
echo "#define SMTP_SERVER ${{ secrets.smtp_server }}" >> secret.h
|
||||
echo "${{ secrets.cesiumkey }}" >> inner_templates/googlemaps/cesium-key.js
|
||||
cd ..
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
qmake
|
||||
cd src
|
||||
echo "#define STRAVA_SECRET_KEY ${{ secrets.strava_secret_key }}" > secret.h
|
||||
echo "#define SMTP_USERNAME ${{ secrets.smtp_username }}" >> secret.h
|
||||
echo "#define SMTP_PASSWORD ${{ secrets.smtp_password }}" >> secret.h
|
||||
echo "#define SMTP_SERVER ${{ secrets.smtp_server }}" >> secret.h
|
||||
cd ..
|
||||
make -j8
|
||||
cd src/debug
|
||||
mkdir output
|
||||
@@ -143,17 +133,15 @@ jobs:
|
||||
cp qdomyos-zwift.exe output/
|
||||
cd output
|
||||
windeployqt --qmldir ../../ qdomyos-zwift.exe
|
||||
cp "C:/mingw64/bin/libwinpthread-1.dll" .
|
||||
cp "C:/mingw64/bin/libgcc_s_seh-1.dll" .
|
||||
cp "C:/mingw64/bin/libstdc++-6.dll" .
|
||||
cp "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 .
|
||||
cp ../../windows/*.bat .
|
||||
cp ../../../windows_openssl/*.* .
|
||||
mkdir adb
|
||||
mkdir python
|
||||
Copy-Item -Path C:\hostedtoolcache\windows\Python\3.7.9\x64 -Destination python -Recurse
|
||||
Copy-Item -Path C:\hostedtoolcache\windows\Python\3.10.11\x64 -Destination python -Recurse
|
||||
cp ../../adb/* adb/
|
||||
cd ..
|
||||
cd appx
|
||||
@@ -163,6 +151,12 @@ jobs:
|
||||
- name: Build without python
|
||||
run: |
|
||||
qmake
|
||||
cd src
|
||||
echo "#define STRAVA_SECRET_KEY ${{ secrets.strava_secret_key }}" > secret.h
|
||||
echo "#define SMTP_USERNAME ${{ secrets.smtp_username }}" >> secret.h
|
||||
echo "#define SMTP_PASSWORD ${{ secrets.smtp_password }}" >> secret.h
|
||||
echo "#define SMTP_SERVER ${{ secrets.smtp_server }}" >> secret.h
|
||||
cd ..
|
||||
make -j8
|
||||
cd src/debug
|
||||
mkdir output
|
||||
@@ -170,12 +164,11 @@ jobs:
|
||||
cp qdomyos-zwift.exe output/
|
||||
cd output
|
||||
windeployqt --qmldir ../../ qdomyos-zwift.exe
|
||||
cp "C:/mingw64/bin/libwinpthread-1.dll" .
|
||||
cp "C:/mingw64/bin/libgcc_s_seh-1.dll" .
|
||||
cp "C:/mingw64/bin/libstdc++-6.dll" .
|
||||
cp "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_openssl/*.* .
|
||||
mkdir adb
|
||||
cp ../../adb/* adb/
|
||||
cd ..
|
||||
@@ -183,79 +176,23 @@ jobs:
|
||||
#../../MSIX-Toolkit/WindowsSDK/10/10.0.20348.0/x64/makeappx.exe pack /d ../output/ /p qz
|
||||
if: matrix.config.python == false
|
||||
|
||||
- name: patching qt for bluetooth
|
||||
run: cp qt-patches/windows/5.15.2/binary/mingw64/*.* ${{ github.workspace }}/src/debug/output/
|
||||
|
||||
- name: Zip artifact for deployment
|
||||
run: Compress-Archive src/debug/output windows-binary.zip
|
||||
if: matrix.config.python
|
||||
|
||||
- name: Zip artifact for deployment
|
||||
run: Compress-Archive src/debug/output windows-binary-no-python.zip
|
||||
if: ${{ ! matrix.config.python }}
|
||||
run: Compress-Archive src/debug/output release.zip
|
||||
|
||||
- name: Archive windows binary
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: windows-binary
|
||||
path: windows-binary.zip
|
||||
path: release.zip
|
||||
if: matrix.config.python
|
||||
|
||||
- name: Archive windows binary
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: windows-binary-no-python
|
||||
path: windows-binary-no-python.zip
|
||||
path: release.zip
|
||||
if: ${{ ! matrix.config.python }}
|
||||
|
||||
# - name: Exit if not on master branch
|
||||
# if: github.ref == 'refs/heads/main'
|
||||
# run: exit 1
|
||||
|
||||
# - uses: actions/checkout@v3
|
||||
# with:
|
||||
# fetch-depth: 0 # Required due to the way Git works, without it this action won't be able to find any or the correct tags
|
||||
|
||||
# - name: Get previous tag
|
||||
# id: previoustag
|
||||
# uses: 'WyriHaximus/github-action-get-previous-tag@v1'
|
||||
# env:
|
||||
# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
# - name: Create Release
|
||||
# if: ${{ ! matrix.config.python }}
|
||||
# id: create_release
|
||||
# uses: actions/create-release@v1
|
||||
# env:
|
||||
# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
# with:
|
||||
# tag_name: ${{ steps.previoustag.outputs.tag }}
|
||||
# release_name: Release ${{ steps.previoustag.outputs.tag }}
|
||||
# draft: false
|
||||
# prerelease: false
|
||||
|
||||
# - name: upload windows artifact
|
||||
# uses: actions/upload-release-asset@v1
|
||||
# if: ${{ ! matrix.config.python }}
|
||||
# env:
|
||||
# GITHUB_TOKEN: ${{ github.token }}
|
||||
# with:
|
||||
# upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
# asset_path: release.zip
|
||||
# asset_name: windows-binary-no-python.zip
|
||||
# asset_content_type: application/zip
|
||||
|
||||
# - name: upload windows artifact
|
||||
# uses: actions/upload-release-asset@v1
|
||||
# if: ${{ matrix.config.python }}
|
||||
# env:
|
||||
# GITHUB_TOKEN: ${{ github.token }}
|
||||
# with:
|
||||
# upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
# asset_path: release.zip
|
||||
# asset_name: windows-binary.zip
|
||||
# asset_content_type: application/zip
|
||||
|
||||
# window-steam-build:
|
||||
# runs-on: windows-latest
|
||||
#
|
||||
@@ -306,7 +243,6 @@ jobs:
|
||||
# echo "#define SMTP_USERNAME ${{ secrets.smtp_username }}" >> secret.h
|
||||
# echo "#define SMTP_PASSWORD ${{ secrets.smtp_password }}" >> secret.h
|
||||
# echo "#define SMTP_SERVER ${{ secrets.smtp_server }}" >> secret.h
|
||||
# echo "${{ secrets.cesiumkey }}" >> inner_templates/googlemaps/cesium-key.js
|
||||
# echo "#define STEAM_STORE" >> secret.h
|
||||
# cd ..
|
||||
# make -j8
|
||||
@@ -341,19 +277,6 @@ jobs:
|
||||
|
||||
# Steps represent a sequence of tasks that will be executed as part of the job
|
||||
steps:
|
||||
- name: release
|
||||
uses: actions/create-release@v1
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
id: create_release
|
||||
with:
|
||||
draft: false
|
||||
prerelease: false
|
||||
release_name: ${{ steps.version.outputs.version }}
|
||||
tag_name: ${{ github.ref }}
|
||||
body_path: CHANGELOG.md
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ github.token }}
|
||||
|
||||
# - name: Cache Qt Linux Desktop
|
||||
# id: cache-qt-linux-desktop
|
||||
# uses: actions/cache@v1
|
||||
@@ -530,12 +453,30 @@ jobs:
|
||||
sudo apt-get install -y xvfb
|
||||
Xvfb -ac ${{ env.DISPLAY }} -screen 0 1280x780x24 &
|
||||
|
||||
- name: Checkout repository
|
||||
# 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:
|
||||
# This token is provided by Actions, you do not need to create your own token
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
submodules: recursive # or 'true' if you want to check out only immediate submodules
|
||||
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 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
|
||||
@@ -572,7 +513,7 @@ jobs:
|
||||
- name: Install Qt Android
|
||||
uses: jurplel/install-qt-action@v3
|
||||
with:
|
||||
version: '5.15.0'
|
||||
version: '5.15.2'
|
||||
host: 'linux'
|
||||
target: 'android'
|
||||
arch: 'android'
|
||||
@@ -586,20 +527,6 @@ jobs:
|
||||
with:
|
||||
distribution: 'temurin' # See 'Supported distributions' for available options
|
||||
java-version: '11'
|
||||
|
||||
- name: patching qt for bluetooth
|
||||
run: cp qt-patches/android/5.15.0/jar/*.* ${{ github.workspace }}/output/android/Qt/5.15.0/android/jar/
|
||||
|
||||
- name: download 3rd party files for qthttpserver
|
||||
run: cp qHttpServerBin/5.15.2/headers/* src/qthttpserver/src/3rdparty/http-parser/
|
||||
|
||||
- name: Build qthttpserver
|
||||
run: |
|
||||
cd src/qthttpserver
|
||||
qmake
|
||||
make -j8
|
||||
make install
|
||||
cd ../..
|
||||
|
||||
- name: Set Android NDK 21 && build
|
||||
run: |
|
||||
@@ -611,49 +538,17 @@ jobs:
|
||||
echo "y" | $SDKMANAGER "ndk;21.4.7075529"
|
||||
export ANDROID_NDK="${ANDROID_SDK_ROOT}/ndk-bundle"
|
||||
export ANDROID_NDK_ROOT="${ANDROID_NDK}"
|
||||
cd src
|
||||
echo "#define STRAVA_SECRET_KEY ${{ secrets.strava_secret_key }}" > secret.h
|
||||
echo "#define SMTP_USERNAME ${{ secrets.smtp_username }}" >> secret.h
|
||||
echo "#define SMTP_PASSWORD ${{ secrets.smtp_password }}" >> secret.h
|
||||
echo "#define SMTP_SERVER ${{ secrets.smtp_server }}" >> secret.h
|
||||
echo "${{ secrets.cesiumkey }}" >> inner_templates/googlemaps/cesium-key.js
|
||||
echo "#define LICENSE" >> secret.h
|
||||
cd ..
|
||||
|
||||
ln -sfn $ANDROID_SDK_ROOT/ndk/21.4.7075529 $ANDROID_NDK
|
||||
rm -rf /usr/local/lib/android/sdk/ndk/25.1.8937393
|
||||
qmake -spec android-clang 'ANDROID_ABIS=armeabi-v7a arm64-v8a x86 x86_64' 'ANDROID_NDK_ROOT=/usr/local/lib/android/sdk/ndk/21.4.7075529' && make -j4 && make INSTALL_ROOT=${{ github.workspace }}/output/android/ install
|
||||
sed -i '1s|{|{\n "android-extra-libs": "${{ github.workspace }}/android_openssl/no-asm/latest/arm/libcrypto_1_1.so,${{ github.workspace }}/android_openssl/no-asm/latest/arm/libssl_1_1.so,${{ github.workspace }}/android_openssl/no-asm/latest/arm64/libcrypto_1_1.so,${{ github.workspace }}/android_openssl/no-asm/latest/arm64/libssl_1_1.so,${{ github.workspace }}/android_openssl/no-asm/latest/x86/libcrypto_1_1.so,${{ github.workspace }}/android_openssl/no-asm/latest/x86/libssl_1_1.so,${{ github.workspace }}/android_openssl/no-asm/latest/x86_64/libcrypto_1_1.so,${{ github.workspace }}/android_openssl/no-asm/latest/x86_64/libssl_1_1.so",|' src/android-qdomyos-zwift-deployment-settings.json
|
||||
cat src/android-qdomyos-zwift-deployment-settings.json
|
||||
|
||||
- name: Build APK (not usable for production due to unpatched QT library)
|
||||
run: cd src; androiddeployqt --input android-qdomyos-zwift-deployment-settings.json --output ${{ github.workspace }}/output/android/ --android-platform android-31 --gradle --aab
|
||||
|
||||
- name: Archive apk binary
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: fdroid-android-trial
|
||||
path: ${{ github.workspace }}/output/android/build/outputs/apk/debug/
|
||||
|
||||
# - name: Exit if not on master branch
|
||||
# if: github.ref == 'refs/heads/main'
|
||||
# run: exit 1
|
||||
|
||||
# - name: upload windows artifact
|
||||
# uses: actions/upload-release-asset@v1
|
||||
# env:
|
||||
# GITHUB_TOKEN: ${{ github.token }}
|
||||
# with:
|
||||
# upload_url: ${{ steps.create_release.outputs.upload_url }}
|
||||
# asset_path: ${{ github.workspace }}/output/android/build/outputs/apk/debug/android-debug.apk
|
||||
# asset_name: fdroid-android-trial.zip
|
||||
# asset_content_type: application/zip
|
||||
|
||||
ios-build:
|
||||
# The type of runner that the job will run on
|
||||
runs-on: macos-latest
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
steps:
|
||||
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
|
||||
@@ -705,342 +600,5 @@ jobs:
|
||||
run: cp qt-patches/ios/5.15.2/binary/*.* ${{ github.workspace }}/output/ios/Qt/5.15.2/ios/lib/
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
cd src
|
||||
echo "#define STRAVA_SECRET_KEY ${{ secrets.strava_secret_key }}" > secret.h
|
||||
echo "#define SMTP_USERNAME ${{ secrets.smtp_username }}" >> secret.h
|
||||
echo "#define SMTP_PASSWORD ${{ secrets.smtp_password }}" >> secret.h
|
||||
echo "#define SMTP_SERVER ${{ secrets.smtp_server }}" >> secret.h
|
||||
echo "${{ secrets.cesiumkey }}" >> inner_templates/googlemaps/cesium-key.js
|
||||
cd ..
|
||||
qmake CONFIG+=debug && make -j4
|
||||
run: qmake CONFIG+=debug && make -j4
|
||||
|
||||
# causes iOS build on Mac to fail
|
||||
# - name: Commit moc files
|
||||
# uses: EndBug/add-and-commit@v9
|
||||
# with:
|
||||
# message: 'moc files added'
|
||||
# add: 'src/moc_*.cpp --force'
|
||||
# if: github.ref == 'refs/heads/master'
|
||||
|
||||
window-msvc2019-build:
|
||||
runs-on: windows-latest
|
||||
strategy:
|
||||
matrix:
|
||||
config:
|
||||
- {python: true}
|
||||
- {python: false}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Checkout submodule repo
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: bluetiger9/SmtpClient-for-Qt
|
||||
path: "src/smtpclient/"
|
||||
ref: 3fa4a0fe5797070339422cf18b5e9ed8dcb91f9c
|
||||
|
||||
- uses: actions/checkout@v2
|
||||
- name: Checkout submodule repo
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: cagnulein/qmdnsengine
|
||||
path: "src/qmdnsengine/"
|
||||
ref: "zwift"
|
||||
|
||||
- uses: actions/checkout@v2
|
||||
- name: Checkout submodule repo
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: google/googletest
|
||||
path: "tst/googletest/"
|
||||
ref: "release-1.12.1"
|
||||
|
||||
- uses: actions/checkout@v2
|
||||
- name: Checkout qHttpServer
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: qt-labs/qthttpserver
|
||||
path: "src/qthttpserver"
|
||||
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: 3.7
|
||||
- name: download python and paddleocr
|
||||
run: |
|
||||
python -VV
|
||||
python -m pip install --upgrade pip
|
||||
python -m pip install --upgrade setuptools
|
||||
python -m pip install "protobuf<=3.20.2,>=3.1.0"
|
||||
python -m pip install paddlepaddle==2.5.1
|
||||
python -m pip install paddleocr
|
||||
python -m pip install imutils
|
||||
python -m pip install "Pillow<10.0.0"
|
||||
python -m pip install opencv-python
|
||||
python -m pip install numpy
|
||||
python -m pip install pywin32
|
||||
if: matrix.config.python
|
||||
|
||||
- name: Install Qt
|
||||
uses: jurplel/install-qt-action@v3
|
||||
with:
|
||||
version: '5.15.2'
|
||||
host: 'windows'
|
||||
modules: 'qtnetworkauth qtcharts'
|
||||
target: "desktop"
|
||||
arch: win64_msvc2019_64
|
||||
dir: "${{github.workspace}}/qt/"
|
||||
install-deps: "true"
|
||||
cache: 'true'
|
||||
cache-key-prefix: 'install-qt-action-windows'
|
||||
|
||||
- name: Install MSVC compiler
|
||||
uses: ilammy/msvc-dev-cmd@v1
|
||||
with:
|
||||
# 14.1 is for vs2017, 14.2 is vs2019, following the upstream vcpkg build from Qv2ray-deps repo
|
||||
toolset: 14.2
|
||||
arch: x64
|
||||
|
||||
- name: download 3rd party files for qthttpserver
|
||||
run: |
|
||||
cp qHttpServerBin/5.15.2/headers/* src/qthttpserver/src/3rdparty/http-parser/
|
||||
|
||||
- name: Build qthttpserver
|
||||
run: |
|
||||
cd src\qthttpserver
|
||||
qmake
|
||||
nmake
|
||||
nmake install
|
||||
cd ../..
|
||||
|
||||
- name: Secrets
|
||||
if: github.ref == 'refs/heads/main'
|
||||
run: |
|
||||
cd src
|
||||
echo "#define STRAVA_SECRET_KEY ${{ secrets.strava_secret_key }}" > secret.h
|
||||
echo "#define SMTP_USERNAME ${{ secrets.smtp_username }}" >> secret.h
|
||||
echo "#define SMTP_PASSWORD ${{ secrets.smtp_password }}" >> secret.h
|
||||
echo "#define SMTP_SERVER ${{ secrets.smtp_server }}" >> secret.h
|
||||
echo "${{ secrets.cesiumkey }}" >> inner_templates/googlemaps/cesium-key.js
|
||||
cd ..
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
qmake
|
||||
nmake
|
||||
cd src/debug
|
||||
mkdir output
|
||||
mkdir appx
|
||||
cp qdomyos-zwift.exe output/
|
||||
cd output
|
||||
windeployqt --qmldir ../../ qdomyos-zwift.exe
|
||||
cp ../../../icons/iOS/iTunesArtwork@2x.png .
|
||||
cp ../../AppxManifest.xml .
|
||||
cp ../../windows/*.py .
|
||||
cp ../../windows/*.bat .
|
||||
cp ../../../windows_openssl/*.* .
|
||||
mkdir adb
|
||||
mkdir python
|
||||
Copy-Item -Path C:\hostedtoolcache\windows\Python\3.7.9\x64 -Destination python -Recurse
|
||||
cp ../../adb/* adb/
|
||||
cd ..
|
||||
cd appx
|
||||
#../../MSIX-Toolkit/WindowsSDK/10/10.0.20348.0/x64/makeappx.exe pack /d ../output/ /p qz
|
||||
if: matrix.config.python
|
||||
|
||||
- name: Build without python
|
||||
run: |
|
||||
qmake
|
||||
nmake
|
||||
cd src/debug
|
||||
mkdir output
|
||||
mkdir appx
|
||||
cp qdomyos-zwift.exe output/
|
||||
cd output
|
||||
windeployqt --qmldir ../../ qdomyos-zwift.exe
|
||||
cp "C:/mingw64/bin/libwinpthread-1.dll" .
|
||||
cp "C:/mingw64/bin/libgcc_s_seh-1.dll" .
|
||||
cp "C:/mingw64/bin/libstdc++-6.dll" .
|
||||
cp ../../../icons/iOS/iTunesArtwork@2x.png .
|
||||
cp ../../AppxManifest.xml .
|
||||
cp ../../../windows_openssl/*.* .
|
||||
mkdir adb
|
||||
cp ../../adb/* adb/
|
||||
cd ..
|
||||
cd appx
|
||||
#../../MSIX-Toolkit/WindowsSDK/10/10.0.20348.0/x64/makeappx.exe pack /d ../output/ /p qz
|
||||
if: matrix.config.python == false
|
||||
|
||||
- name: patching qt for bluetooth
|
||||
run: cp qt-patches/windows/5.15.2/binary/msvc2019/*.* ${{ github.workspace }}/src/debug/output/
|
||||
|
||||
- name: Zip artifact for deployment
|
||||
run: Compress-Archive src/debug/output windows-msvc2019-binary.zip
|
||||
if: matrix.config.python
|
||||
|
||||
- name: Zip artifact for deployment
|
||||
run: Compress-Archive src/debug/output windows-msvc2019-binary-no-python.zip
|
||||
if: ${{ ! matrix.config.python }}
|
||||
|
||||
- name: Archive windows binary
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: windows-msvc2019-binary
|
||||
path: windows-msvc2019-binary.zip
|
||||
if: matrix.config.python
|
||||
|
||||
- name: Archive windows binary
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: windows-msvc2019-binary-no-python
|
||||
path: windows-msvc2019-binary-no-python.zip
|
||||
if: ${{ ! matrix.config.python }}
|
||||
|
||||
window-msvc2019-aiserver-build:
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Checkout submodule repo
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: bluetiger9/SmtpClient-for-Qt
|
||||
path: "src/smtpclient/"
|
||||
ref: 3fa4a0fe5797070339422cf18b5e9ed8dcb91f9c
|
||||
|
||||
- uses: actions/checkout@v2
|
||||
- name: Checkout submodule repo
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: cagnulein/qmdnsengine
|
||||
path: "src/qmdnsengine/"
|
||||
ref: "zwift"
|
||||
|
||||
- uses: actions/checkout@v2
|
||||
- name: Checkout submodule repo
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: google/googletest
|
||||
path: "tst/googletest/"
|
||||
ref: "release-1.12.1"
|
||||
|
||||
- uses: actions/checkout@v2
|
||||
- name: Checkout qHttpServer
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: qt-labs/qthttpserver
|
||||
path: "src/qthttpserver"
|
||||
|
||||
- name: Install Qt
|
||||
uses: jurplel/install-qt-action@v3
|
||||
with:
|
||||
version: '5.15.2'
|
||||
host: 'windows'
|
||||
modules: 'qtnetworkauth qtcharts'
|
||||
target: "desktop"
|
||||
arch: win64_msvc2019_64
|
||||
dir: "${{github.workspace}}/qt/"
|
||||
install-deps: "true"
|
||||
cache: 'true'
|
||||
cache-key-prefix: 'install-qt-action-windows'
|
||||
|
||||
- name: Install MSVC compiler
|
||||
uses: ilammy/msvc-dev-cmd@v1
|
||||
with:
|
||||
# 14.1 is for vs2017, 14.2 is vs2019, following the upstream vcpkg build from Qv2ray-deps repo
|
||||
toolset: 14.2
|
||||
arch: x64
|
||||
|
||||
- name: download 3rd party files for qthttpserver
|
||||
run: |
|
||||
cp qHttpServerBin/5.15.2/headers/* src/qthttpserver/src/3rdparty/http-parser/
|
||||
|
||||
- name: Build qthttpserver
|
||||
run: |
|
||||
cd src\qthttpserver
|
||||
qmake
|
||||
nmake
|
||||
nmake install
|
||||
cd ../..
|
||||
|
||||
- name: Secrets
|
||||
if: github.ref == 'refs/heads/main'
|
||||
run: |
|
||||
cd src
|
||||
echo "#define STRAVA_SECRET_KEY ${{ secrets.strava_secret_key }}" > secret.h
|
||||
echo "#define SMTP_USERNAME ${{ secrets.smtp_username }}" >> secret.h
|
||||
echo "#define SMTP_PASSWORD ${{ secrets.smtp_password }}" >> secret.h
|
||||
echo "#define SMTP_SERVER ${{ secrets.smtp_server }}" >> secret.h
|
||||
echo "${{ secrets.cesiumkey }}" >> inner_templates/googlemaps/cesium-key.js
|
||||
cd ..
|
||||
|
||||
- name: Build
|
||||
run: |
|
||||
cd src
|
||||
echo "#define AISERVER" >> aiserver.h
|
||||
cd ..
|
||||
qmake
|
||||
nmake
|
||||
cd src/debug
|
||||
mkdir output
|
||||
mkdir appx
|
||||
cp qdomyos-zwift.exe output/
|
||||
cd output
|
||||
windeployqt --qmldir ../../ qdomyos-zwift.exe
|
||||
cp ../../../icons/iOS/iTunesArtwork@2x.png .
|
||||
cp ../../AppxManifest.xml .
|
||||
cp ../../windows/zwift-incline-ai-server.py zwift-incline.py
|
||||
cp ../../windows/zwift-incline-climb-portal-ai-server.py zwift-incline-climb-portal.py
|
||||
cp ../../windows/zwift-workout-ai-server.py zwift-workout.py
|
||||
cp ../../windows/*.bat .
|
||||
cp ../../../windows_openssl/*.* .
|
||||
mkdir adb
|
||||
cp ../../adb/* adb/
|
||||
cd ..
|
||||
cd appx
|
||||
#../../MSIX-Toolkit/WindowsSDK/10/10.0.20348.0/x64/makeappx.exe pack /d ../output/ /p qz
|
||||
|
||||
- name: patching qt for bluetooth
|
||||
run: cp qt-patches/windows/5.15.2/binary/msvc2019/*.* ${{ github.workspace }}/src/debug/output/
|
||||
|
||||
- name: Zip artifact for deployment
|
||||
run: Compress-Archive src/debug/output windows-msvc2019-ai-server-binary.zip
|
||||
|
||||
- name: Archive windows binary
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: windows-msvc2019-ai-server-binary
|
||||
path: windows-msvc2019-ai-server-binary.zip
|
||||
|
||||
upload_to_release:
|
||||
permissions: write-all
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event_name == 'schedule'
|
||||
needs: [linux-x86-build, window-msvc2019-build, ios-build, window-build, android-build] # Specify the job dependencies
|
||||
steps:
|
||||
- name: Download artifacts
|
||||
uses: actions/download-artifact@v3
|
||||
- name: Update nightly release
|
||||
uses: andelf/nightly-release@main
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
with:
|
||||
tag_name: nightly
|
||||
prerelease: false
|
||||
name: 'QZ nightly build $$'
|
||||
body: |
|
||||
This is a nightly build of QZ.
|
||||
|
||||
You can use this if you want to try new features without waiting for releases.
|
||||
From time to time, in development builds, old difficult-to-reproduce bugs are
|
||||
fixed, but it is also true that in the development process with the introduction
|
||||
of new complex code, the stability of the program may suffer compared to
|
||||
official releases, so **use it with caution**!
|
||||
|
||||
__Please help us improve QZ by reporting any issues you encounter!__ :wink:
|
||||
files: |
|
||||
windows-msvc2019-binary-no-python/*
|
||||
windows-msvc2019-binary/*
|
||||
windows-msvc2019-ai-server-binary/*
|
||||
windows-binary-no-python/*
|
||||
windows-binary/*
|
||||
fdroid-android-trial/*
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -49,4 +49,3 @@ src/inner_templates/googlemaps/cesium-key.js
|
||||
*.autosave
|
||||
.vscode/settings.json
|
||||
/tst/Devices/.vs
|
||||
src/inner_templates/googlemaps/cesium-key.js
|
||||
|
||||
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -13,6 +13,3 @@
|
||||
path = tst/googletest
|
||||
url = https://github.com/google/googletest.git
|
||||
branch = tags/release-1.12.1
|
||||
[submodule "src/qthttpserver"]
|
||||
path = src/qthttpserver
|
||||
url = https://github.com/qt-labs/qthttpserver
|
||||
|
||||
112
README.md
112
README.md
@@ -7,99 +7,35 @@ Zwift bridge for Treadmills and Bike!
|
||||
[<img src="docs/img/app_store.png">](https://apps.apple.com/app/id1543684531?fbclid=IwAR10H6y3mEgwkTlGJON3e8voYOh2wt3kLFOpFzoIXaYZ_N0y0pDvKxHMUaM)
|
||||
<a href="https://www.buymeacoffee.com/cagnulein" target="_blank"><img src="https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png" alt="Buy Me A Coffee" style="height: 41px !important;width: 174px !important;box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;" ></a>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
<img src="icons/AppScreen/iOS%20Phones%20-%206.5_/screenshot1.jpeg" style="height: 400px !important; box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;" >
|
||||
</td>
|
||||
<td>
|
||||
<img src="icons/AppScreen/iOS%20Phones%20-%206.5_/screenshot2.jpeg" style="height: 400px !important; box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;" >
|
||||
</td>
|
||||
<td>
|
||||
<img src="icons/AppScreen/iOS%20Phones%20-%206.5_/screenshot3.jpeg" style="height: 400px !important; box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;" >
|
||||
</td>
|
||||
<td>
|
||||
<img src="icons/AppScreen/iOS%20Phones%20-%206.5_/screenshot4.jpeg" style="height: 400px !important; box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;" >
|
||||
</td>
|
||||
<td>
|
||||
<img src="icons/AppScreen/iOS%20Phones%20-%206.5_/screenshot5.jpeg" style="height: 400px !important; box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;-webkit-box-shadow: 0px 3px 2px 0px rgba(190, 190, 190, 0.5) !important;" >
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||

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

|
||||

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

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

|
||||
|
||||
### Installation
|
||||
|
||||
You can install it on multiple platforms.
|
||||
You can install on multiple platforms.
|
||||
Read the [installation procedure](docs/10_Installation.md)
|
||||
|
||||
|
||||
@@ -109,7 +45,7 @@ You can run the app on [Macintosh or Linux devices](docs/10_Installation.md). IO
|
||||
|
||||
QDomyos-Zwift works on every [FTMS-compatible application](docs/20_supported_devices_and_applications.md), and virtually any [bluetooth enabled device](docs/20_supported_devices_and_applications.md).
|
||||
|
||||
### No GUI version
|
||||
### No gui version
|
||||
|
||||
run as
|
||||
|
||||
@@ -121,7 +57,7 @@ https://github.com/ProH4Ck/treadmill-bridge
|
||||
|
||||
https://www.livestrong.com/article/422012-what-is-10-degrees-in-incline-on-a-treadmill/
|
||||
|
||||
Icons used in this documentation come from [flaticon.com](https://www.flaticon.com)
|
||||
Icons used in this documentation comes from [flaticon.com](https://www.flaticon.com)
|
||||
|
||||
### Blog
|
||||
|
||||
|
||||
@@ -2,4 +2,3 @@
|
||||
// Use this file to import your target's public headers that you would like to expose to Swift.
|
||||
//
|
||||
|
||||
#import "swiftDebug.h"
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 54;
|
||||
objectVersion = 52;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXAggregateTarget section */
|
||||
@@ -114,9 +114,6 @@
|
||||
7EC1321DD83EAAFAA2B7109C /* domyosbike.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 7944A61A6F17291731CE6F84 /* domyosbike.cpp */; settings = {ATTRIBUTES = (); }; };
|
||||
8556B13A3D02D52A21FC5E3E /* bluetooth.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = B0BE11FB9531A6AD480B20E7 /* bluetooth.cpp */; settings = {ATTRIBUTES = (); }; };
|
||||
868B65D0AB5114A4A0D5479E /* qmldbg_messages in Link Binary With Libraries */ = {isa = PBXBuildFile; fileRef = 008F20821C7E4D5F7DB55754 /* qmldbg_messages */; };
|
||||
8701142A2B14D5A800193FC6 /* moc_eliteariafan.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 870114292B14D5A800193FC6 /* moc_eliteariafan.cpp */; };
|
||||
8701142D2B14D5C600193FC6 /* eliteariafan.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 8701142C2B14D5C600193FC6 /* eliteariafan.cpp */; };
|
||||
870114302B14D5F400193FC6 /* ios_eliteariafan.mm in Compile Sources */ = {isa = PBXBuildFile; fileRef = 8701142E2B14D5F400193FC6 /* ios_eliteariafan.mm */; };
|
||||
8703BAEB273C67A90058E206 /* pafersbike.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 8703BAE9273C67A90058E206 /* pafersbike.cpp */; };
|
||||
8703BAED273C67B60058E206 /* moc_pafersbike.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 8703BAEC273C67B50058E206 /* moc_pafersbike.cpp */; };
|
||||
87061390286D8B4F00D2446E /* libQt5PositioningQuick.a in Link Binary With Libraries */ = {isa = PBXBuildFile; fileRef = 8706138F286D8B4F00D2446E /* libQt5PositioningQuick.a */; };
|
||||
@@ -173,10 +170,6 @@
|
||||
872261F0289EA887006A6F75 /* moc_nordictrackelliptical.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 872261EF289EA887006A6F75 /* moc_nordictrackelliptical.cpp */; };
|
||||
8727A47727849EA600019B5D /* paferstreadmill.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 8727A47627849EA600019B5D /* paferstreadmill.cpp */; };
|
||||
8727A47927849EB200019B5D /* moc_paferstreadmill.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 8727A47827849EB200019B5D /* moc_paferstreadmill.cpp */; };
|
||||
8727C7D02B3BF1B8005429EB /* proformtelnetbike.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 8727C7CC2B3BF1B8005429EB /* proformtelnetbike.cpp */; };
|
||||
8727C7D12B3BF1B8005429EB /* QTelnet.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 8727C7CF2B3BF1B8005429EB /* QTelnet.cpp */; };
|
||||
8727C7D42B3BF1E4005429EB /* moc_QTelnet.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 8727C7D22B3BF1E4005429EB /* moc_QTelnet.cpp */; };
|
||||
8727C7D52B3BF1E4005429EB /* moc_proformtelnetbike.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 8727C7D32B3BF1E4005429EB /* moc_proformtelnetbike.cpp */; };
|
||||
872A20DA28C5EC380037774D /* faketreadmill.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 872A20D928C5EC380037774D /* faketreadmill.cpp */; };
|
||||
872A20DC28C5F5CE0037774D /* moc_faketreadmill.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 872A20DB28C5F5CE0037774D /* moc_faketreadmill.cpp */; };
|
||||
872BAB4E261750EE006A59AB /* libQt5Charts.a in Link Binary With Libraries */ = {isa = PBXBuildFile; fileRef = 872BAB4D261750EE006A59AB /* libQt5Charts.a */; };
|
||||
@@ -261,16 +254,11 @@
|
||||
87433F2127D8B722003D1672 /* simplecrypt.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87433F2027D8B722003D1672 /* simplecrypt.cpp */; };
|
||||
87440FBD2640291700E4DC0B /* fitplusbike.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87440FBC2640291700E4DC0B /* fitplusbike.cpp */; };
|
||||
87440FBF2640292900E4DC0B /* moc_fitplusbike.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87440FBE2640292900E4DC0B /* moc_fitplusbike.cpp */; };
|
||||
8745B2762AFCB4A300991A39 /* android in Copy Bundle Resources */ = {isa = PBXBuildFile; fileRef = 8745B2752AFCB4A300991A39 /* android */; };
|
||||
8745B2782AFCB87B00991A39 /* libadb.a in Link Binary With Libraries */ = {isa = PBXBuildFile; fileRef = 8745B2742AFCB3B300991A39 /* libadb.a */; };
|
||||
87473A9627ECA9EE00C203F5 /* proformrower.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87473A9527ECA9EE00C203F5 /* proformrower.cpp */; };
|
||||
87473A9827ECAA0500C203F5 /* moc_proformrower.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87473A9727ECAA0500C203F5 /* moc_proformrower.cpp */; };
|
||||
874D272029AFA11F0007C079 /* apexbike.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 874D271E29AFA11F0007C079 /* apexbike.cpp */; };
|
||||
874D272229AFA13B0007C079 /* moc_apexbike.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 874D272129AFA13B0007C079 /* moc_apexbike.cpp */; };
|
||||
8752B4CD27F43D9200E2EC6C /* qz.storekit in Copy Bundle Resources */ = {isa = PBXBuildFile; fileRef = 8752B4CC27F43D9200E2EC6C /* qz.storekit */; };
|
||||
8752C0E32B15D84100C3D1A5 /* moc_eliteariafan.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 8752C0E22B15D84100C3D1A5 /* moc_eliteariafan.cpp */; };
|
||||
8752C0E82B15D85600C3D1A5 /* eliteariafan.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 8752C0E42B15D85600C3D1A5 /* eliteariafan.cpp */; };
|
||||
8752C0E92B15D85600C3D1A5 /* ios_eliteariafan.mm in Compile Sources */ = {isa = PBXBuildFile; fileRef = 8752C0E62B15D85600C3D1A5 /* ios_eliteariafan.mm */; };
|
||||
87540FAD2848FD70005E0D44 /* libqtexttospeech_speechios.a in Link Binary With Libraries */ = {isa = PBXBuildFile; fileRef = 87540FAC2848FD70005E0D44 /* libqtexttospeech_speechios.a */; };
|
||||
8754D24C27F786F0003D7054 /* virtualrower.swift in Compile Sources */ = {isa = PBXBuildFile; fileRef = 8754D24B27F786F0003D7054 /* virtualrower.swift */; };
|
||||
87586A4125B8340E00A243C4 /* proformbike.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87586A4025B8340E00A243C4 /* proformbike.cpp */; };
|
||||
@@ -374,7 +362,6 @@
|
||||
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 */; };
|
||||
87A2E0222B2B053E00E6168F /* swiftDebug.mm in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87A2E0212B2B053E00E6168F /* swiftDebug.mm */; };
|
||||
87A3BC222656429600D302E3 /* rower.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87A3BC1F2656429400D302E3 /* rower.cpp */; };
|
||||
87A3BC232656429600D302E3 /* echelonrower.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87A3BC202656429400D302E3 /* echelonrower.cpp */; };
|
||||
87A3BC26265642A300D302E3 /* moc_rower.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87A3BC24265642A200D302E3 /* moc_rower.cpp */; };
|
||||
@@ -827,11 +814,6 @@
|
||||
867187CB3CB3703D1925C88A /* fit_weather_conditions_mesg_listener.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = fit_weather_conditions_mesg_listener.hpp; path = "/Users/cagnulein/qdomyos-zwift/src/fit-sdk/fit_weather_conditions_mesg_listener.hpp"; sourceTree = "<absolute>"; };
|
||||
86DD72842A64993F31E31719 /* fit_ant_rx_mesg_listener.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = fit_ant_rx_mesg_listener.hpp; path = "/Users/cagnulein/qdomyos-zwift/src/fit-sdk/fit_ant_rx_mesg_listener.hpp"; sourceTree = "<absolute>"; };
|
||||
86F10E1AE2D47520E65C0543 /* fit_dive_summary_mesg_listener.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = fit_dive_summary_mesg_listener.hpp; path = "/Users/cagnulein/qdomyos-zwift/src/fit-sdk/fit_dive_summary_mesg_listener.hpp"; sourceTree = "<absolute>"; };
|
||||
870114292B14D5A800193FC6 /* moc_eliteariafan.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = moc_eliteariafan.cpp; sourceTree = "<group>"; };
|
||||
8701142B2B14D5C600193FC6 /* eliteariafan.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = eliteariafan.h; path = ../src/eliteariafan.h; sourceTree = "<group>"; };
|
||||
8701142C2B14D5C600193FC6 /* eliteariafan.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = eliteariafan.cpp; path = ../src/eliteariafan.cpp; sourceTree = "<group>"; };
|
||||
8701142E2B14D5F400193FC6 /* ios_eliteariafan.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = ios_eliteariafan.mm; path = ../src/ios/ios_eliteariafan.mm; sourceTree = "<group>"; };
|
||||
8701142F2B14D5F400193FC6 /* ios_eliteariafan.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ios_eliteariafan.h; path = ../src/ios/ios_eliteariafan.h; sourceTree = "<group>"; };
|
||||
8703BAE9273C67A90058E206 /* pafersbike.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = pafersbike.cpp; path = ../src/pafersbike.cpp; sourceTree = "<group>"; };
|
||||
8703BAEA273C67A90058E206 /* pafersbike.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = pafersbike.h; path = ../src/pafersbike.h; sourceTree = "<group>"; };
|
||||
8703BAEC273C67B50058E206 /* moc_pafersbike.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = moc_pafersbike.cpp; sourceTree = "<group>"; };
|
||||
@@ -899,13 +881,6 @@
|
||||
8727A47527849EA600019B5D /* paferstreadmill.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = paferstreadmill.h; path = ../src/paferstreadmill.h; sourceTree = "<group>"; };
|
||||
8727A47627849EA600019B5D /* paferstreadmill.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = paferstreadmill.cpp; path = ../src/paferstreadmill.cpp; sourceTree = "<group>"; };
|
||||
8727A47827849EB200019B5D /* moc_paferstreadmill.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = moc_paferstreadmill.cpp; sourceTree = "<group>"; };
|
||||
8727C7CC2B3BF1B8005429EB /* proformtelnetbike.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = proformtelnetbike.cpp; path = ../src/proformtelnetbike.cpp; sourceTree = "<group>"; };
|
||||
8727C7CD2B3BF1B8005429EB /* proformtelnetbike.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = proformtelnetbike.h; path = ../src/proformtelnetbike.h; sourceTree = "<group>"; };
|
||||
8727C7CE2B3BF1B8005429EB /* QTelnet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = QTelnet.h; path = ../src/QTelnet.h; sourceTree = "<group>"; };
|
||||
8727C7CF2B3BF1B8005429EB /* QTelnet.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = QTelnet.cpp; path = ../src/QTelnet.cpp; sourceTree = "<group>"; };
|
||||
8727C7D22B3BF1E4005429EB /* moc_QTelnet.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = moc_QTelnet.cpp; sourceTree = "<group>"; };
|
||||
8727C7D32B3BF1E4005429EB /* moc_proformtelnetbike.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = moc_proformtelnetbike.cpp; sourceTree = "<group>"; };
|
||||
8729149E2B2B010600565E33 /* qdomyoszwift-Bridging-Header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "qdomyoszwift-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||
872A20D828C5EC380037774D /* faketreadmill.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = faketreadmill.h; path = ../src/faketreadmill.h; sourceTree = "<group>"; };
|
||||
872A20D928C5EC380037774D /* faketreadmill.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = faketreadmill.cpp; path = ../src/faketreadmill.cpp; sourceTree = "<group>"; };
|
||||
872A20DB28C5F5CE0037774D /* moc_faketreadmill.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = moc_faketreadmill.cpp; sourceTree = "<group>"; };
|
||||
@@ -1031,9 +1006,6 @@
|
||||
87440FBB2640291700E4DC0B /* fitplusbike.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = fitplusbike.h; path = ../src/fitplusbike.h; sourceTree = "<group>"; };
|
||||
87440FBC2640291700E4DC0B /* fitplusbike.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = fitplusbike.cpp; path = ../src/fitplusbike.cpp; sourceTree = "<group>"; };
|
||||
87440FBE2640292900E4DC0B /* moc_fitplusbike.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = moc_fitplusbike.cpp; sourceTree = "<group>"; };
|
||||
8745B2742AFCB3B300991A39 /* libadb.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libadb.a; path = ../src/ios/libadb.a; sourceTree = "<group>"; };
|
||||
8745B2752AFCB4A300991A39 /* android */ = {isa = PBXFileReference; lastKnownFileType = folder; name = android; path = ../src/ios/android; sourceTree = "<group>"; };
|
||||
8745B2772AFCB52800991A39 /* AdbClient.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AdbClient.h; path = ../src/ios/AdbClient.h; sourceTree = "<group>"; };
|
||||
87473A9427ECA9EE00C203F5 /* proformrower.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = proformrower.h; path = ../src/proformrower.h; sourceTree = "<group>"; };
|
||||
87473A9527ECA9EE00C203F5 /* proformrower.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = proformrower.cpp; path = ../src/proformrower.cpp; sourceTree = "<group>"; };
|
||||
87473A9727ECAA0500C203F5 /* moc_proformrower.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = moc_proformrower.cpp; sourceTree = "<group>"; };
|
||||
@@ -1041,11 +1013,6 @@
|
||||
874D271F29AFA11F0007C079 /* apexbike.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = apexbike.h; path = ../src/apexbike.h; sourceTree = "<group>"; };
|
||||
874D272129AFA13B0007C079 /* moc_apexbike.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = moc_apexbike.cpp; sourceTree = "<group>"; };
|
||||
8752B4CC27F43D9200E2EC6C /* qz.storekit */ = {isa = PBXFileReference; lastKnownFileType = text; path = qz.storekit; sourceTree = "<group>"; };
|
||||
8752C0E22B15D84100C3D1A5 /* moc_eliteariafan.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = moc_eliteariafan.cpp; sourceTree = "<group>"; };
|
||||
8752C0E42B15D85600C3D1A5 /* eliteariafan.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = eliteariafan.cpp; path = ../src/eliteariafan.cpp; sourceTree = "<group>"; };
|
||||
8752C0E52B15D85600C3D1A5 /* eliteariafan.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = eliteariafan.h; path = ../src/eliteariafan.h; sourceTree = "<group>"; };
|
||||
8752C0E62B15D85600C3D1A5 /* ios_eliteariafan.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = ios_eliteariafan.mm; path = ../src/ios/ios_eliteariafan.mm; sourceTree = "<group>"; };
|
||||
8752C0E72B15D85600C3D1A5 /* ios_eliteariafan.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ios_eliteariafan.h; path = ../src/ios/ios_eliteariafan.h; sourceTree = "<group>"; };
|
||||
87540FAC2848FD70005E0D44 /* libqtexttospeech_speechios.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libqtexttospeech_speechios.a; path = ../../Qt/5.15.2/ios/plugins/texttospeech/libqtexttospeech_speechios.a; sourceTree = "<group>"; };
|
||||
8754D24B27F786F0003D7054 /* virtualrower.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = virtualrower.swift; path = ../src/ios/virtualrower.swift; sourceTree = "<group>"; };
|
||||
87586A3F25B8340D00A243C4 /* proformbike.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = proformbike.h; path = ../src/proformbike.h; sourceTree = "<group>"; };
|
||||
@@ -1201,8 +1168,6 @@
|
||||
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>"; };
|
||||
87A2E0202B2B024200E6168F /* swiftDebug.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = swiftDebug.h; path = ../src/ios/swiftDebug.h; sourceTree = "<group>"; };
|
||||
87A2E0212B2B053E00E6168F /* swiftDebug.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = swiftDebug.mm; path = ../src/ios/swiftDebug.mm; sourceTree = "<group>"; };
|
||||
87A3BC1E2656429300D302E3 /* echelonrower.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = echelonrower.h; path = ../src/echelonrower.h; sourceTree = "<group>"; };
|
||||
87A3BC1F2656429400D302E3 /* rower.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = rower.cpp; path = ../src/rower.cpp; sourceTree = "<group>"; };
|
||||
87A3BC202656429400D302E3 /* echelonrower.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = echelonrower.cpp; path = ../src/echelonrower.cpp; sourceTree = "<group>"; };
|
||||
@@ -1599,7 +1564,6 @@
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
8745B2782AFCB87B00991A39 /* libadb.a in Link Binary With Libraries */,
|
||||
879F74112893D5B8009A64C8 /* libqavfcamera.a in Link Binary With Libraries */,
|
||||
879F740F2893D592009A64C8 /* libqtmedia_audioengine.a in Link Binary With Libraries */,
|
||||
879F740C2893D4FA009A64C8 /* libqtaudio_coreaudio.a in Link Binary With Libraries */,
|
||||
@@ -1925,20 +1889,6 @@
|
||||
2EB56BE3C2D93CDAB0C52E67 /* Sources */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
8727C7D32B3BF1E4005429EB /* moc_proformtelnetbike.cpp */,
|
||||
8727C7D22B3BF1E4005429EB /* moc_QTelnet.cpp */,
|
||||
8727C7CC2B3BF1B8005429EB /* proformtelnetbike.cpp */,
|
||||
8727C7CD2B3BF1B8005429EB /* proformtelnetbike.h */,
|
||||
8727C7CF2B3BF1B8005429EB /* QTelnet.cpp */,
|
||||
8727C7CE2B3BF1B8005429EB /* QTelnet.h */,
|
||||
87A2E0212B2B053E00E6168F /* swiftDebug.mm */,
|
||||
8729149E2B2B010600565E33 /* qdomyoszwift-Bridging-Header.h */,
|
||||
8752C0E42B15D85600C3D1A5 /* eliteariafan.cpp */,
|
||||
8752C0E52B15D85600C3D1A5 /* eliteariafan.h */,
|
||||
8752C0E72B15D85600C3D1A5 /* ios_eliteariafan.h */,
|
||||
8752C0E62B15D85600C3D1A5 /* ios_eliteariafan.mm */,
|
||||
8752C0E22B15D84100C3D1A5 /* moc_eliteariafan.cpp */,
|
||||
8745B2772AFCB52800991A39 /* AdbClient.h */,
|
||||
87A0D7502A3A4517005147F2 /* fakerower.cpp */,
|
||||
87A0D7512A3A4517005147F2 /* fakerower.h */,
|
||||
878D83732A1F33C600D7F004 /* bkoolbike.cpp */,
|
||||
@@ -2296,7 +2246,6 @@
|
||||
35E903698E72424585D33829 /* virtualtreadmill.h */,
|
||||
C8CE72E7B224D8B886614E3F /* domyosbike.h */,
|
||||
8710707229C4A5E70094D0F3 /* GarminConnect.swift */,
|
||||
87A2E0202B2B024200E6168F /* swiftDebug.h */,
|
||||
);
|
||||
name = Sources;
|
||||
sourceTree = "<group>";
|
||||
@@ -2389,7 +2338,6 @@
|
||||
AF39DD055C3EF8226FBE929D /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
8745B2742AFCB3B300991A39 /* libadb.a */,
|
||||
873D388A29B0D744006A2611 /* ConnectIQ.xcframework */,
|
||||
879F74142893D732009A64C8 /* CoreMedia.framework */,
|
||||
879F74122893D705009A64C8 /* CoreVideo.framework */,
|
||||
@@ -2779,7 +2727,6 @@
|
||||
E8C543AB96796ECAA2E65C57 /* qdomyoszwift */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
8745B2752AFCB4A300991A39 /* android */,
|
||||
8752B4CC27F43D9200E2EC6C /* qz.storekit */,
|
||||
2EB56BE3C2D93CDAB0C52E67 /* Sources */,
|
||||
25B08E2869634E9BCBA333A2 /* Generated Sources */,
|
||||
@@ -2916,7 +2863,6 @@
|
||||
isa = PBXResourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
8745B2762AFCB4A300991A39 /* android in Copy Bundle Resources */,
|
||||
87C5F0BC26285E5F0067A1B5 /* SmtpMime in Copy Bundle Resources */,
|
||||
2188AA0A52E9CD610922F82E /* Default-568h@2x.png in Copy Bundle Resources */,
|
||||
8752B4CD27F43D9200E2EC6C /* qz.storekit in Copy Bundle Resources */,
|
||||
@@ -3039,8 +2985,6 @@
|
||||
87DF68BD25E2675100FCDA46 /* moc_eslinkertreadmill.cpp in Compile Sources */,
|
||||
87646C2027B5064600F82131 /* bhfitnesselliptical.cpp in Compile Sources */,
|
||||
8718CBAD263063CE004BF4EE /* moc_templateinfosender.cpp in Compile Sources */,
|
||||
8752C0E32B15D84100C3D1A5 /* moc_eliteariafan.cpp in Compile Sources */,
|
||||
8752C0E92B15D85600C3D1A5 /* ios_eliteariafan.mm in Compile Sources */,
|
||||
87C5F0D326285E7E0067A1B5 /* moc_mimecontentformatter.cpp in Compile Sources */,
|
||||
8718CBAB263063CE004BF4EE /* moc_templateinfosenderbuilder.cpp in Compile Sources */,
|
||||
C6B3CD471768392E18F85819 /* fit_accumulated_field.cpp in Compile Sources */,
|
||||
@@ -3048,10 +2992,8 @@
|
||||
2A61806454201575EDB3F94F /* fit_buffer_encode.cpp in Compile Sources */,
|
||||
87F02E4229178545000DB52C /* moc_octaneelliptical.cpp in Compile Sources */,
|
||||
87E2F85D291ED308002BDC65 /* lifefitnesstreadmill.cpp in Compile Sources */,
|
||||
8752C0E82B15D85600C3D1A5 /* eliteariafan.cpp in Compile Sources */,
|
||||
87917A7328E768D200F8D9AC /* Browser.swift in Compile Sources */,
|
||||
873CD20B27EF8D8A000131BC /* inapptransaction.cpp in Compile Sources */,
|
||||
8727C7D52B3BF1E4005429EB /* moc_proformtelnetbike.cpp in Compile Sources */,
|
||||
873824EF27E647A9004F1B46 /* query.cpp in Compile Sources */,
|
||||
876F45FF279350D9003CDA5A /* moc_concept2skierg.cpp in Compile Sources */,
|
||||
BE93C6EF2C2A6BFEEC9EA565 /* fit_buffered_mesg_broadcaster.cpp in Compile Sources */,
|
||||
@@ -3185,7 +3127,6 @@
|
||||
87EB918727EE5FE7002535E1 /* moc_nautilusbike.cpp in Compile Sources */,
|
||||
873824B827E64707004F1B46 /* moc_cache.cpp in Compile Sources */,
|
||||
873824E427E647A8004F1B46 /* cache.cpp in Compile Sources */,
|
||||
87A2E0222B2B053E00E6168F /* swiftDebug.mm in Compile Sources */,
|
||||
87310B1E266FBB59008BA0D6 /* smartrowrower.cpp in Compile Sources */,
|
||||
87A3BC222656429600D302E3 /* rower.cpp in Compile Sources */,
|
||||
C719682D8D421AF6B2DAAEA9 /* main.cpp in Compile Sources */,
|
||||
@@ -3287,7 +3228,6 @@
|
||||
873824E727E647A8004F1B46 /* record.cpp in Compile Sources */,
|
||||
B38F3288D4AE4025465C1953 /* moc_bike.cpp in Compile Sources */,
|
||||
87EFB57025BD704A0039DD5A /* moc_proformtreadmill.cpp in Compile Sources */,
|
||||
8727C7D42B3BF1E4005429EB /* moc_QTelnet.cpp in Compile Sources */,
|
||||
C3D1FD2587BF6F15B58BA675 /* moc_bluetooth.cpp in Compile Sources */,
|
||||
87062648259480B700D06586 /* WorkoutTracking.swift in Compile Sources */,
|
||||
8C3422A825EF7ECD78951307 /* moc_bluetoothdevice.cpp in Compile Sources */,
|
||||
@@ -3336,7 +3276,6 @@
|
||||
87D269A025F535200076AA48 /* skandikawiribike.cpp in Compile Sources */,
|
||||
8738249427E646E3004F1B46 /* characteristicnotifier2a5b.cpp in Compile Sources */,
|
||||
8768D1FB285081FE00F58E3A /* nordictrackifitadbtreadmill.cpp in Compile Sources */,
|
||||
8727C7D12B3BF1B8005429EB /* QTelnet.cpp in Compile Sources */,
|
||||
8775008329E876F8008E48B7 /* iconceptelliptical.cpp in Compile Sources */,
|
||||
87B187BD29B8C577007EEF9D /* moc_ziprotreadmill.cpp in Compile Sources */,
|
||||
877FBA2B276E684E00F6C0C9 /* moc_bowflextreadmill.cpp in Compile Sources */,
|
||||
@@ -3368,7 +3307,6 @@
|
||||
8703BAED273C67B60058E206 /* moc_pafersbike.cpp in Compile Sources */,
|
||||
873824E627E647A8004F1B46 /* hostname.cpp in Compile Sources */,
|
||||
74C43649C9C4E2E5F9378019 /* moc_domyosbike.cpp in Compile Sources */,
|
||||
8727C7D02B3BF1B8005429EB /* proformtelnetbike.cpp in Compile Sources */,
|
||||
87E0761D277A081A00FDA0F9 /* technogymmyruntreadmillrfcomm.cpp in Compile Sources */,
|
||||
873824B327E64707004F1B46 /* moc_dirconprocessor.cpp in Compile Sources */,
|
||||
87A0771229B6420200A368BF /* moc_wahookickrheadwind.cpp in Compile Sources */,
|
||||
@@ -3728,7 +3666,7 @@
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 693;
|
||||
CURRENT_PROJECT_VERSION = 612;
|
||||
DEVELOPMENT_TEAM = 6335M7T29D;
|
||||
ENABLE_BITCODE = NO;
|
||||
HEADER_SEARCH_PATHS = (
|
||||
@@ -3802,9 +3740,8 @@
|
||||
/Users/cagnulein/Qt/5.15.2/ios/plugins/mediaservice,
|
||||
/Users/cagnulein/Qt/5.15.2/ios/plugins/playlistformats,
|
||||
/Users/cagnulein/Qt/5.15.2/ios/plugins/audio,
|
||||
"/Users/cagnulein/qdomyos-zwift/src/ios",
|
||||
);
|
||||
MARKETING_VERSION = 2.16;
|
||||
MARKETING_VERSION = 2.13;
|
||||
OTHER_CFLAGS = (
|
||||
"-pipe",
|
||||
"-g",
|
||||
@@ -3881,7 +3818,6 @@
|
||||
QT_LIBRARY_SUFFIX = "";
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_INSTALL_OBJC_HEADER = YES;
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "qdomyoszwift-Bridging-Header.h";
|
||||
SWIFT_OBJC_INTERFACE_HEADER_NAME = "$(SWIFT_MODULE_NAME)-Swift2.h";
|
||||
SWIFT_PRECOMPILE_BRIDGING_HEADER = YES;
|
||||
SWIFT_VERSION = 5.0;
|
||||
@@ -3898,7 +3834,7 @@
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements";
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 693;
|
||||
CURRENT_PROJECT_VERSION = 612;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
DEVELOPMENT_TEAM = 6335M7T29D;
|
||||
ENABLE_BITCODE = NO;
|
||||
@@ -3974,9 +3910,8 @@
|
||||
/Users/cagnulein/Qt/5.15.2/ios/plugins/mediaservice,
|
||||
/Users/cagnulein/Qt/5.15.2/ios/plugins/playlistformats,
|
||||
/Users/cagnulein/Qt/5.15.2/ios/plugins/audio,
|
||||
"/Users/cagnulein/qdomyos-zwift/src/ios",
|
||||
);
|
||||
MARKETING_VERSION = 2.16;
|
||||
MARKETING_VERSION = 2.13;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
OTHER_CFLAGS = (
|
||||
"-pipe",
|
||||
@@ -4054,7 +3989,6 @@
|
||||
QT_LIBRARY_SUFFIX = _debug;
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_INSTALL_OBJC_HEADER = YES;
|
||||
SWIFT_OBJC_BRIDGING_HEADER = "qdomyoszwift-Bridging-Header.h";
|
||||
SWIFT_OBJC_INTERFACE_HEADER_NAME = "$(SWIFT_MODULE_NAME)-Swift2.h";
|
||||
SWIFT_PRECOMPILE_BRIDGING_HEADER = YES;
|
||||
SWIFT_VERSION = 5.0;
|
||||
@@ -4104,7 +4038,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements";
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 693;
|
||||
CURRENT_PROJECT_VERSION = 612;
|
||||
DEVELOPMENT_TEAM = 6335M7T29D;
|
||||
ENABLE_BITCODE = YES;
|
||||
ENABLE_STRICT_OBJC_MSGSEND = YES;
|
||||
@@ -4129,7 +4063,7 @@
|
||||
"@executable_path/../Frameworks",
|
||||
"@loader_path/../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 2.16;
|
||||
MARKETING_VERSION = 2.13;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
OTHER_CODE_SIGN_FLAGS = "--generate-entitlement-der";
|
||||
@@ -4200,7 +4134,7 @@
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 693;
|
||||
CURRENT_PROJECT_VERSION = 612;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
DEVELOPMENT_TEAM = 6335M7T29D;
|
||||
ENABLE_BITCODE = YES;
|
||||
@@ -4221,7 +4155,7 @@
|
||||
"@executable_path/../Frameworks",
|
||||
"@loader_path/../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 2.16;
|
||||
MARKETING_VERSION = 2.13;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
MTL_FAST_MATH = YES;
|
||||
OTHER_CODE_SIGN_FLAGS = "--generate-entitlement-der";
|
||||
@@ -4292,7 +4226,7 @@
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 693;
|
||||
CURRENT_PROJECT_VERSION = 612;
|
||||
DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\"";
|
||||
ENABLE_BITCODE = YES;
|
||||
ENABLE_PREVIEWS = YES;
|
||||
@@ -4337,7 +4271,7 @@
|
||||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 2.16;
|
||||
MARKETING_VERSION = 2.13;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
OTHER_CODE_SIGN_FLAGS = "--generate-entitlement-der";
|
||||
@@ -4406,7 +4340,7 @@
|
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
|
||||
CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 693;
|
||||
CURRENT_PROJECT_VERSION = 612;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\"";
|
||||
ENABLE_BITCODE = YES;
|
||||
@@ -4447,7 +4381,7 @@
|
||||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 2.16;
|
||||
MARKETING_VERSION = 2.13;
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
MTL_FAST_MATH = YES;
|
||||
OTHER_CODE_SIGN_FLAGS = "--generate-entitlement-der";
|
||||
|
||||
@@ -104,9 +104,6 @@ extension MainController: WorkoutTrackingDelegate {
|
||||
"\(heartRate)" as AnyObject])
|
||||
WorkoutTracking.distance = WatchKitConnection.distance
|
||||
WorkoutTracking.kcal = WatchKitConnection.kcal
|
||||
WorkoutTracking.speed = WatchKitConnection.speed
|
||||
WorkoutTracking.power = WatchKitConnection.power
|
||||
WorkoutTracking.cadence = WatchKitConnection.cadence
|
||||
|
||||
if Locale.current.measurementSystem != "Metric" {
|
||||
self.distanceLabel.setText("Distance \(String(format:"%.2f", WorkoutTracking.distance))")
|
||||
|
||||
@@ -24,9 +24,6 @@ class WatchKitConnection: NSObject {
|
||||
public static var distance = 0.0
|
||||
public static var kcal = 0.0
|
||||
public static var stepCadence = 0
|
||||
public static var speed = 0.0
|
||||
public static var cadence = 0.0
|
||||
public static var power = 0.0
|
||||
weak var delegate: WatchKitConnectionDelegate?
|
||||
|
||||
private override init() {
|
||||
@@ -69,13 +66,6 @@ extension WatchKitConnection: WatchKitConnectionProtocol {
|
||||
WatchKitConnection.distance = dDistance
|
||||
let dKcal = Double(result["kcal"] as! Double)
|
||||
WatchKitConnection.kcal = dKcal
|
||||
|
||||
let dSpeed = Double(result["speed"] as! Double)
|
||||
WatchKitConnection.speed = dSpeed
|
||||
let dPower = Double(result["power"] as! Double)
|
||||
WatchKitConnection.power = dPower
|
||||
let dCadence = Double(result["cadence"] as! Double)
|
||||
WatchKitConnection.cadence = dCadence
|
||||
}, errorHandler: { (error) in
|
||||
print(error)
|
||||
})
|
||||
|
||||
@@ -31,10 +31,6 @@ class WorkoutTracking: NSObject {
|
||||
public static var cadenceTimeStamp = NSDate().timeIntervalSince1970
|
||||
public static var cadenceLastSteps = Double()
|
||||
public static var cadenceSteps = 0
|
||||
public static var speed = Double()
|
||||
public static var power = Double()
|
||||
public static var cadence = Double()
|
||||
public static var lastDateMetric = Date()
|
||||
var sport: Int = 0
|
||||
let healthStore = HKHealthStore()
|
||||
let configuration = HKWorkoutConfiguration()
|
||||
@@ -150,37 +146,14 @@ extension WorkoutTracking: WorkoutTrackingProtocol {
|
||||
HKSampleType.workoutType()
|
||||
])
|
||||
|
||||
var infoToShare: Set<HKSampleType> = []
|
||||
|
||||
if #available(watchOSApplicationExtension 10.0, *) {
|
||||
infoToShare = Set([
|
||||
HKSampleType.quantityType(forIdentifier: .stepCount)!,
|
||||
HKSampleType.quantityType(forIdentifier: .heartRate)!,
|
||||
HKSampleType.quantityType(forIdentifier: .distanceCycling)!,
|
||||
HKSampleType.quantityType(forIdentifier: .distanceWalkingRunning)!,
|
||||
HKSampleType.quantityType(forIdentifier: .activeEnergyBurned)!,
|
||||
HKSampleType.quantityType(forIdentifier: .cyclingPower)!,
|
||||
HKSampleType.quantityType(forIdentifier: .cyclingSpeed)!,
|
||||
HKSampleType.quantityType(forIdentifier: .cyclingCadence)!,
|
||||
HKSampleType.quantityType(forIdentifier: .runningPower)!,
|
||||
HKSampleType.quantityType(forIdentifier: .runningSpeed)!,
|
||||
HKSampleType.quantityType(forIdentifier: .runningStrideLength)!,
|
||||
HKSampleType.quantityType(forIdentifier: .runningVerticalOscillation)!,
|
||||
HKSampleType.quantityType(forIdentifier: .walkingSpeed)!,
|
||||
HKSampleType.quantityType(forIdentifier: .walkingStepLength)!,
|
||||
HKSampleType.workoutType()
|
||||
])
|
||||
} else {
|
||||
// Fallback on earlier versions
|
||||
infoToShare = Set([
|
||||
HKSampleType.quantityType(forIdentifier: .stepCount)!,
|
||||
HKSampleType.quantityType(forIdentifier: .heartRate)!,
|
||||
HKSampleType.quantityType(forIdentifier: .distanceCycling)!,
|
||||
HKSampleType.quantityType(forIdentifier: .distanceWalkingRunning)!,
|
||||
HKSampleType.quantityType(forIdentifier: .activeEnergyBurned)!,
|
||||
HKSampleType.workoutType()
|
||||
])
|
||||
}
|
||||
let infoToShare = Set([
|
||||
HKSampleType.quantityType(forIdentifier: .stepCount)!,
|
||||
HKSampleType.quantityType(forIdentifier: .heartRate)!,
|
||||
HKSampleType.quantityType(forIdentifier: .distanceCycling)!,
|
||||
HKSampleType.quantityType(forIdentifier: .distanceWalkingRunning)!,
|
||||
HKSampleType.quantityType(forIdentifier: .activeEnergyBurned)!,
|
||||
HKSampleType.workoutType()
|
||||
])
|
||||
|
||||
HKHealthStore().requestAuthorization(toShare: infoToShare, read: infoToRead) { (success, error) in
|
||||
if success {
|
||||
@@ -195,7 +168,6 @@ extension WorkoutTracking: WorkoutTrackingProtocol {
|
||||
}
|
||||
|
||||
func startWorkOut() {
|
||||
WorkoutTracking.lastDateMetric = Date()
|
||||
print("Start workout")
|
||||
configWorkout()
|
||||
workoutSession.startActivity(with: Date())
|
||||
@@ -340,135 +312,6 @@ extension WorkoutTracking: HKLiveWorkoutBuilderDelegate {
|
||||
handleSendStatisticsData(statistics)
|
||||
}
|
||||
}
|
||||
|
||||
if(sport == 0) {
|
||||
if #available(watchOSApplicationExtension 10.0, *) {
|
||||
let wattPerInterval = HKQuantity(unit: HKUnit.watt(),
|
||||
doubleValue: WorkoutTracking.power)
|
||||
|
||||
if(WorkoutTracking.lastDateMetric.distance(to: Date()) < 1) {
|
||||
return
|
||||
}
|
||||
|
||||
guard let powerType = HKQuantityType.quantityType(
|
||||
forIdentifier: .cyclingPower) else {
|
||||
return
|
||||
}
|
||||
let wattPerIntervalSample = HKQuantitySample(type: powerType,
|
||||
quantity: wattPerInterval,
|
||||
start: WorkoutTracking.lastDateMetric,
|
||||
end: Date())
|
||||
workoutBuilder.add([wattPerIntervalSample]) {(success, error) in
|
||||
if let error = error {
|
||||
print(error)
|
||||
}
|
||||
}
|
||||
|
||||
let cadencePerInterval = HKQuantity(unit: HKUnit.count().unitDivided(by: HKUnit.second()),
|
||||
doubleValue: WorkoutTracking.cadence / 60.0)
|
||||
|
||||
guard let cadenceType = HKQuantityType.quantityType(
|
||||
forIdentifier: .cyclingCadence) else {
|
||||
return
|
||||
}
|
||||
let cadencePerIntervalSample = HKQuantitySample(type: cadenceType,
|
||||
quantity: cadencePerInterval,
|
||||
start: WorkoutTracking.lastDateMetric,
|
||||
end: Date())
|
||||
workoutBuilder.add([cadencePerIntervalSample]) {(success, error) in
|
||||
if let error = error {
|
||||
print(error)
|
||||
}
|
||||
}
|
||||
|
||||
let speedPerInterval = HKQuantity(unit: HKUnit.meter().unitDivided(by: HKUnit.second()),
|
||||
doubleValue: WorkoutTracking.speed * 0.277778)
|
||||
|
||||
guard let speedType = HKQuantityType.quantityType(
|
||||
forIdentifier: .cyclingSpeed) else {
|
||||
return
|
||||
}
|
||||
let speedPerIntervalSample = HKQuantitySample(type: speedType,
|
||||
quantity: speedPerInterval,
|
||||
start: WorkoutTracking.lastDateMetric,
|
||||
end: Date())
|
||||
workoutBuilder.add([speedPerIntervalSample]) {(success, error) in
|
||||
if let error = error {
|
||||
print(error)
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
// Fallback on earlier versions
|
||||
}
|
||||
} else if(sport == 1) {
|
||||
if #available(watchOSApplicationExtension 10.0, *) {
|
||||
let wattPerInterval = HKQuantity(unit: HKUnit.watt(),
|
||||
doubleValue: WorkoutTracking.power)
|
||||
|
||||
if(WorkoutTracking.lastDateMetric.distance(to: Date()) < 1) {
|
||||
return
|
||||
}
|
||||
|
||||
guard let powerType = HKQuantityType.quantityType(
|
||||
forIdentifier: .runningPower) else {
|
||||
return
|
||||
}
|
||||
let wattPerIntervalSample = HKQuantitySample(type: powerType,
|
||||
quantity: wattPerInterval,
|
||||
start: WorkoutTracking.lastDateMetric,
|
||||
end: Date())
|
||||
workoutBuilder.add([wattPerIntervalSample]) {(success, error) in
|
||||
if let error = error {
|
||||
print(error)
|
||||
}
|
||||
}
|
||||
|
||||
let speedPerInterval = HKQuantity(unit: HKUnit.meter().unitDivided(by: HKUnit.second()),
|
||||
doubleValue: WorkoutTracking.speed * 0.277778)
|
||||
|
||||
guard let speedType = HKQuantityType.quantityType(
|
||||
forIdentifier: .runningSpeed) else {
|
||||
return
|
||||
}
|
||||
let speedPerIntervalSample = HKQuantitySample(type: speedType,
|
||||
quantity: speedPerInterval,
|
||||
start: WorkoutTracking.lastDateMetric,
|
||||
end: Date())
|
||||
workoutBuilder.add([speedPerIntervalSample]) {(success, error) in
|
||||
if let error = error {
|
||||
print(error)
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
// Fallback on earlier versions
|
||||
}
|
||||
} else if(sport == 2) {
|
||||
if #available(watchOSApplicationExtension 10.0, *) {
|
||||
let speedPerInterval = HKQuantity(unit: HKUnit.meter().unitDivided(by: HKUnit.second()),
|
||||
doubleValue: WorkoutTracking.speed * 0.277778)
|
||||
|
||||
guard let speedType = HKQuantityType.quantityType(
|
||||
forIdentifier: .walkingSpeed) else {
|
||||
return
|
||||
}
|
||||
let speedPerIntervalSample = HKQuantitySample(type: speedType,
|
||||
quantity: speedPerInterval,
|
||||
start: WorkoutTracking.lastDateMetric,
|
||||
end: Date())
|
||||
workoutBuilder.add([speedPerIntervalSample]) {(success, error) in
|
||||
if let error = error {
|
||||
print(error)
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
// Fallback on earlier versions
|
||||
}
|
||||
}
|
||||
|
||||
WorkoutTracking.lastDateMetric = Date()
|
||||
}
|
||||
|
||||
func workoutBuilderDidCollectEvent(_ workoutBuilder: HKLiveWorkoutBuilder) {
|
||||
|
||||
@@ -28,7 +28,7 @@ $ sudo ./qdomyos-zwift
|
||||
You will need to (at a minimum) to install the xcode Command Line Tools (CLI) thanks to @richardwait
|
||||
https://developer.apple.com/download/more/?=xcode
|
||||
|
||||
Download and install https://download.qt.io/archive/qt/5.12/5.12.12/qt-opensource-mac-x64-5.12.12.dmg and simply run the qdomyos-zwift release for MacOs
|
||||
Download and install http://download.qt.io/official_releases/qt/5.12/5.12.9/qt-opensource-mac-x64-5.12.9.dmg and simply run the qdomyos-zwift release for MacOs
|
||||
|
||||
## On Raspberry Pi Zero W
|
||||
|
||||
@@ -77,7 +77,7 @@ Apply the changes `sudo systemctl restart dhcpcd.service` and ensure you have in
|
||||
|
||||
#### Enable SSH access
|
||||
|
||||
You might want to access your raspberry remotely while it is attached to your fitness equipment.
|
||||
You might want to access your raspberry remotely while it is attached to your fitness equipement.
|
||||
|
||||
`sudo raspi-config` > `Interface Options` > `SSH`
|
||||
|
||||
@@ -175,7 +175,7 @@ Then reboot to check operations (`sudo reboot`)
|
||||
|
||||
### (optional) Enable overlay FS
|
||||
|
||||
Once that everything is working as expected, and if you dedicate your Raspberry pi to this usage, you might want to enable the read-only overlay FS.
|
||||
Once that everything is working as expected, and if you dedicate your raspeberry pi to this usage, you might want to enable the read-only overlay FS.
|
||||
|
||||
By enabling the overlay read-only system, your SD card will be read-only only and every file written will be to RAM.
|
||||
Then at each reboot the RAM is erased and you'll revert to the initial status of the overlay file-system.
|
||||
|
||||
@@ -18,7 +18,7 @@ Please refer to this article for more information under [QML Operations](https:/
|
||||
|
||||
## Configuration in NativeQT mode
|
||||
|
||||
This is the list of settings available in the application. These settings need to be appended to the binary command line.
|
||||
This is the list of settings available in the application. These settings needs to be appended to the binary command line.
|
||||
*Example :* `sudo ./qdomyos-zwift -no-gui` for disabling any graphical interface.
|
||||
|
||||
| **Option** | **Type** | **Default** | **Function** |
|
||||
@@ -35,8 +35,8 @@ This is the list of settings available in the application. These settings need t
|
||||
| -heart-service | Boolean | True | Simulate HR service (required for applications not reading FTMS) |
|
||||
| -only-virtualbike | Boolean | False | |
|
||||
| -only-virtualtreadmill | Boolean | False | |
|
||||
| -no-reconnection | Boolean | False | QZ will not try to reconnect your fitness equipment if enabled |
|
||||
| -bluetooth-relaxed | Boolean | False | In case of deconnections from QZ to your fitness equipment |
|
||||
| -no-reconnection | Boolean | False | QZ will not try to reconnect your fitness equipement if enabled |
|
||||
| -bluetooth-relaxed | Boolean | False | In case of deconnections from QZ to your fitness equipement |
|
||||
| -bike-cadence-sensor | Boolean | False | |
|
||||
| -bike-power-sensor | Boolean | False | |
|
||||
| -battery-service | Boolean | False | |
|
||||
@@ -45,7 +45,7 @@ This is the list of settings available in the application. These settings need t
|
||||
| -run-cadence-sensor | Boolean | False | |
|
||||
| -nordictrack-10-treadmill | Boolean | False | Enable NordicTrack compatibility mode |
|
||||
| -train | String | | Force training program |
|
||||
| -name | String | | Force bluetooth device name (if QZ struggles to find your fitness equipment) |
|
||||
| -name | String | | Force bluetooth device name (if QZ struggles finding your fitness equipment) |
|
||||
| -poll-device-time | Int | 200 (ms) | Frequency to refresh information from QZ to Fitness equipment |
|
||||
| -bike-resistance-gain | Int | | Adjust resistance from the fitness application |
|
||||
| -bike-resistance-offset | Int | | Set another resistance point than default |
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,5 +0,0 @@
|
||||
QMAKE_PRL_BUILD_DIR = C:/qt-everywhere-src-5.15.2/qtconnectivity/src/bluetooth
|
||||
QMAKE_PRO_INPUT = bluetooth.pro
|
||||
QMAKE_PRL_TARGET = Qt5Bluetooth.lib
|
||||
QMAKE_PRL_CONFIG = lex yacc depend_includepath testcase_targets import_plugins import_qpa_plugin windows prepare_docs qt_docs_targets qt_build_extra file_copies qmake_use qt warn_on release link_prl flat debug_and_release precompile_header autogen_precompile_source embed_manifest_dll embed_manifest_exe shared shared release no_plugin_manifest win32 msvc copy_dir_files sse2 aesni sse3 ssse3 sse4_1 sse4_2 avx avx2 avx512f avx512bw avx512cd avx512dq avx512er avx512ifma avx512pf avx512vbmi avx512vl compile_examples f16c force_debug_info largefile precompile_header rdrnd rdseed shani x86SimdAlways prefix_build force_independent utf8_source create_prl link_prl no_private_qt_headers_warning QTDIR_build qt_example_installs exceptions_off testcase_exceptions release ReleaseBuild Release build_pass c++11 generated_privates relative_qt_rpath target_qt c++11 strict_c++ c++14 c++1z qt_install_headers need_fwd_pri qt_install_module debug_and_release build_all create_cmake skip_target_version_ext release ReleaseBuild Release build_pass have_target dll exclusive_builds debug_info no_autoqmake thread moc resources
|
||||
QMAKE_PRL_VERSION = 5.15.2
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,5 +0,0 @@
|
||||
QMAKE_PRL_BUILD_DIR = C:/qt-everywhere-src-5.15.2/qtconnectivity/src/bluetooth
|
||||
QMAKE_PRO_INPUT = bluetooth.pro
|
||||
QMAKE_PRL_TARGET = Qt5Bluetoothd.lib
|
||||
QMAKE_PRL_CONFIG = lex yacc debug depend_includepath testcase_targets import_plugins import_qpa_plugin windows prepare_docs qt_docs_targets qt_build_extra file_copies qmake_use qt warn_on link_prl flat debug_and_release precompile_header autogen_precompile_source embed_manifest_dll embed_manifest_exe shared shared no_plugin_manifest win32 msvc copy_dir_files sse2 aesni sse3 ssse3 sse4_1 sse4_2 avx avx2 avx512f avx512bw avx512cd avx512dq avx512er avx512ifma avx512pf avx512vbmi avx512vl compile_examples f16c force_debug_info largefile precompile_header rdrnd rdseed shani x86SimdAlways prefix_build force_independent utf8_source create_prl link_prl no_private_qt_headers_warning QTDIR_build qt_example_installs exceptions_off testcase_exceptions debug DebugBuild Debug build_pass c++11 generated_privates relative_qt_rpath target_qt c++11 strict_c++ c++14 c++1z qt_install_headers need_fwd_pri qt_install_module debug_and_release build_all create_cmake skip_target_version_ext debug DebugBuild Debug build_pass have_target dll no_plist exclusive_builds debug_info no_autoqmake thread moc resources
|
||||
QMAKE_PRL_VERSION = 5.15.2
|
||||
Binary file not shown.
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,25 +0,0 @@
|
||||
import QtQuick 2.7
|
||||
import QtQuick.Layouts 1.3
|
||||
import QtQuick.Controls 2.15
|
||||
import QtQuick.Controls.Material 2.0
|
||||
import Qt.labs.settings 1.0
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
Loader {
|
||||
id: chartFooterLoader
|
||||
sourceComponent: ChartFooterInnerJS
|
||||
anchors.fill: parent
|
||||
active: false
|
||||
}
|
||||
|
||||
Loader {
|
||||
anchors.fill: parent
|
||||
source: CHARTJS ? "ChartFooterInnerJS.qml":"ChartFooterInnerNoJS.qml"
|
||||
onLoaded: {
|
||||
if(CHARTJS) {
|
||||
chartFooterLoader.active = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
import QtQuick 2.7
|
||||
import QtQuick.Layouts 1.3
|
||||
import QtQuick.Controls 2.15
|
||||
import QtQuick.Controls.Material 2.0
|
||||
import Qt.labs.settings 1.0
|
||||
import QtWebView 1.1
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
Settings {
|
||||
id: settings
|
||||
}
|
||||
WebView {
|
||||
id: webView
|
||||
anchors.fill: parent
|
||||
url: "http://localhost:" + settings.value("template_inner_QZWS_port") + "/chartjs/chartlive.htm"
|
||||
visible: rootItem.chartFooterVisible
|
||||
onLoadingChanged: {
|
||||
if (loadRequest.errorString) {
|
||||
console.error(loadRequest.errorString);
|
||||
console.error("port " + settings.value("template_inner_QZWS_port"));
|
||||
}
|
||||
}
|
||||
onVisibleChanged: {
|
||||
console.log("onVisibleChanged" + visible)
|
||||
if(visible === true) {
|
||||
reload();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
import QtQuick 2.7
|
||||
import QtQuick.Layouts 1.3
|
||||
import QtQuick.Controls 2.15
|
||||
import QtQuick.Controls.Material 2.0
|
||||
import Qt.labs.settings 1.0
|
||||
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
Settings {
|
||||
id: settings
|
||||
}
|
||||
}
|
||||
@@ -37,9 +37,12 @@
|
||||
#include <QThread>
|
||||
|
||||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
#include <windef.h>
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
#include <winbase.h>
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <sys/ioctl.h>
|
||||
#include <termios.h> // unix!!
|
||||
|
||||
@@ -11,7 +11,6 @@ import QtLocation 5.6
|
||||
|
||||
ColumnLayout {
|
||||
signal trainprogram_open_clicked(url name)
|
||||
signal trainprogram_open_other_folder(url name)
|
||||
signal trainprogram_preview(url name)
|
||||
FileDialog {
|
||||
id: fileDialogTrainProgram
|
||||
@@ -19,11 +18,7 @@ ColumnLayout {
|
||||
folder: shortcuts.home
|
||||
onAccepted: {
|
||||
console.log("You chose: " + fileDialogTrainProgram.fileUrl)
|
||||
if(OS_VERSION === "Android") {
|
||||
trainprogram_open_other_folder(fileDialogTrainProgram.fileUrl)
|
||||
} else {
|
||||
trainprogram_open_clicked(fileDialogTrainProgram.fileUrl)
|
||||
}
|
||||
trainprogram_open_clicked(fileDialogTrainProgram.fileUrl)
|
||||
fileDialogTrainProgram.close()
|
||||
}
|
||||
onRejected: {
|
||||
|
||||
102
src/Home.qml
102
src/Home.qml
@@ -291,75 +291,59 @@ HomeForm{
|
||||
}
|
||||
|
||||
footer:
|
||||
Item {
|
||||
width: parent.width
|
||||
height: (rootItem.chartFooterVisible ? parent.height / 4 : parent.height / 2)
|
||||
Rectangle {
|
||||
objectName: "footerrectangle"
|
||||
visible: rootItem.videoVisible
|
||||
anchors.top: gridView.bottom
|
||||
visible: rootItem.chartFooterVisible || rootItem.videoVisible
|
||||
width: parent.width
|
||||
height: parent.height / 2
|
||||
// Removed Timer, Play/Pause/Resume is now done via Homeform.cpp
|
||||
/*
|
||||
Timer {
|
||||
id: pauseTimer
|
||||
interval: 1000; running: true; repeat: true
|
||||
onTriggered: { if(visible == true) { (rootItem.currentSpeed > 0 ?
|
||||
videoPlaybackHalf.play() :
|
||||
videoPlaybackHalf.pause()) } }
|
||||
}
|
||||
*/
|
||||
|
||||
Rectangle {
|
||||
id: chartFooterRectangle
|
||||
visible: rootItem.chartFooterVisible
|
||||
anchors.fill: parent
|
||||
ChartFooter {
|
||||
anchors.fill: parent
|
||||
visible: rootItem.chartFooterVisible
|
||||
onVisibleChanged: {
|
||||
if(visible === true) {
|
||||
console.log("mediaPlayer onCompleted: " + rootItem.videoPath)
|
||||
console.log("videoRate: " + rootItem.videoRate)
|
||||
videoPlaybackHalf.source = rootItem.videoPath
|
||||
//videoPlaybackHalf.playbackRate = rootItem.videoRate
|
||||
|
||||
videoPlaybackHalf.seek(rootItem.videoPosition)
|
||||
videoPlaybackHalf.play()
|
||||
videoPlaybackHalf.muted = rootItem.currentCoordinateValid
|
||||
} else {
|
||||
videoPlaybackHalf.stop()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
objectName: "footerrectangle"
|
||||
visible: rootItem.videoVisible
|
||||
anchors.fill: parent
|
||||
// Removed Timer, Play/Pause/Resume is now done via Homeform.cpp
|
||||
/*
|
||||
Timer {
|
||||
id: pauseTimer
|
||||
interval: 1000; running: true; repeat: true
|
||||
onTriggered: { if(visible == true) { (rootItem.currentSpeed > 0 ?
|
||||
videoPlaybackHalf.play() :
|
||||
videoPlaybackHalf.pause()) } }
|
||||
}
|
||||
*/
|
||||
MediaPlayer {
|
||||
id: videoPlaybackHalf
|
||||
objectName: "videoplaybackhalf"
|
||||
autoPlay: false
|
||||
playbackRate: rootItem.videoRate
|
||||
|
||||
onVisibleChanged: {
|
||||
if(visible === true) {
|
||||
console.log("mediaPlayer onCompleted: " + rootItem.videoPath)
|
||||
console.log("videoRate: " + rootItem.videoRate)
|
||||
videoPlaybackHalf.source = rootItem.videoPath
|
||||
//videoPlaybackHalf.playbackRate = rootItem.videoRate
|
||||
|
||||
videoPlaybackHalf.seek(rootItem.videoPosition)
|
||||
videoPlaybackHalf.play()
|
||||
videoPlaybackHalf.muted = rootItem.currentCoordinateValid
|
||||
} else {
|
||||
videoPlaybackHalf.stop()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
MediaPlayer {
|
||||
id: videoPlaybackHalf
|
||||
objectName: "videoplaybackhalf"
|
||||
autoPlay: false
|
||||
playbackRate: rootItem.videoRate
|
||||
|
||||
onError: {
|
||||
if (videoPlaybackHalf.NoError !== error) {
|
||||
console.log("[qmlvideo] VideoItem.onError error " + error + " errorString " + errorString)
|
||||
}
|
||||
onError: {
|
||||
if (videoPlaybackHalf.NoError !== error) {
|
||||
console.log("[qmlvideo] VideoItem.onError error " + error + " errorString " + errorString)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
VideoOutput {
|
||||
id:videoPlayer
|
||||
anchors.fill: parent
|
||||
source: videoPlaybackHalf
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
VideoOutput {
|
||||
id:videoPlayer
|
||||
anchors.fill: parent
|
||||
source: videoPlaybackHalf
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
property int currentId: -1 // Original position in model
|
||||
|
||||
522
src/QTelnet.cpp
522
src/QTelnet.cpp
@@ -1,522 +0,0 @@
|
||||
#include "QTelnet.h"
|
||||
|
||||
#include "QTelnet.h"
|
||||
#include <QHostAddress>
|
||||
|
||||
const char QTelnet::IACWILL[2] = { IAC, WILL };
|
||||
const char QTelnet::IACWONT[2] = { IAC, WONT };
|
||||
const char QTelnet::IACDO[2] = { IAC, DO };
|
||||
const char QTelnet::IACDONT[2] = { IAC, DONT };
|
||||
const char QTelnet::IACSB[2] = { IAC, SB };
|
||||
const char QTelnet::IACSE[2] = { IAC, SE };
|
||||
|
||||
char QTelnet::_sendCodeArray[2] = { IAC, 0 };
|
||||
char QTelnet::_arrCRLF[2] = { 13, 10 };
|
||||
char QTelnet::_arrCR[2] = { 13, 0 };
|
||||
|
||||
QTelnet::QTelnet(QObject *parent) :
|
||||
QTcpSocket(parent), m_actualSB(0)
|
||||
{
|
||||
connect( this, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(socketError(QAbstractSocket::SocketError)) );
|
||||
connect( this, SIGNAL(readyRead()), this, SLOT(onReadyRead()) );
|
||||
}
|
||||
|
||||
QString QTelnet::peerInfo() const
|
||||
{
|
||||
return QString("%1 (%2):%3").arg(peerName()).arg(peerAddress().toString()).arg(peerPort());
|
||||
}
|
||||
|
||||
bool QTelnet::isConnected() const
|
||||
{
|
||||
return state() == QAbstractSocket::ConnectedState;
|
||||
}
|
||||
|
||||
bool QTelnet::testBinaryMode() const
|
||||
{
|
||||
return m_receivedDX[(unsigned char)TELOPT_BINARY] == DO;
|
||||
}
|
||||
|
||||
void QTelnet::connectToHost(const QString &host, quint16 port)
|
||||
{
|
||||
if( !isConnected() )
|
||||
{
|
||||
resetProtocol();
|
||||
abort();
|
||||
QTcpSocket::connectToHost(host, port);
|
||||
}
|
||||
}
|
||||
|
||||
void QTelnet::sendData(const QByteArray &ba)
|
||||
{
|
||||
if( isConnected() )
|
||||
transpose( ba.constData(), ba.count() );
|
||||
}
|
||||
|
||||
void QTelnet::socketError(QAbstractSocket::SocketError err)
|
||||
{
|
||||
Q_UNUSED(err);
|
||||
disconnectFromHost();
|
||||
}
|
||||
|
||||
void QTelnet::write(const char c)
|
||||
{
|
||||
QTcpSocket::write( (char*)&c, 1 );
|
||||
}
|
||||
|
||||
void QTelnet::setCustomCR(char cr, char cr2)
|
||||
{
|
||||
_arrCR[0] = cr;
|
||||
_arrCR[1] = cr2;
|
||||
}
|
||||
|
||||
void QTelnet::setCustomCRLF(char lf, char cr)
|
||||
{
|
||||
_arrCR[0] = lf;
|
||||
_arrCR[1] = cr;
|
||||
}
|
||||
|
||||
// Envia el codigo de control al servidor.
|
||||
void QTelnet::sendTelnetControl(char codigo)
|
||||
{
|
||||
_sendCodeArray[1] = codigo;
|
||||
QTcpSocket::write(_sendCodeArray, 2);
|
||||
}
|
||||
|
||||
void QTelnet::writeCustomCRLF()
|
||||
{
|
||||
QTcpSocket::write(_arrCRLF, 2);
|
||||
}
|
||||
|
||||
void QTelnet::writeCustomCR()
|
||||
{
|
||||
QTcpSocket::write(_arrCR, 2);
|
||||
}
|
||||
|
||||
/// Resetea los datos del protocolo. Debe llamarse cada vez que se inicia una conexión nueva.
|
||||
void QTelnet::resetProtocol()
|
||||
{
|
||||
for( int i = 0; i < 256; i++ )
|
||||
{
|
||||
m_receivedDX[i] =
|
||||
m_receivedWX[i] =
|
||||
m_sentDX[i] =
|
||||
m_sentWX[i] = 0;
|
||||
m_negotiationState = STATE_DATA;
|
||||
m_buffSB.clear();
|
||||
m_actualSB = 0;
|
||||
}
|
||||
m_oldWinSize.setHeight(-1);
|
||||
m_oldWinSize.setWidth(-1);
|
||||
}
|
||||
|
||||
void QTelnet::sendSB(char code, char *arr, int iLen)
|
||||
{
|
||||
write(IAC);
|
||||
write(SB);
|
||||
write(code);
|
||||
|
||||
QTcpSocket::write(arr, iLen);
|
||||
|
||||
write(IAC);
|
||||
write(SE);
|
||||
}
|
||||
void QTelnet::sendWindowSize()
|
||||
{
|
||||
if( isConnected() && (m_receivedDX[TELOPT_NAWS] == DO) && (m_oldWinSize != m_winSize) )
|
||||
{
|
||||
char size[4];
|
||||
|
||||
m_oldWinSize = m_winSize;
|
||||
size[0] = (m_winSize.width()>>8) & 0xFF;
|
||||
size[1] = m_winSize.width() & 0xFF;
|
||||
size[2] = (m_winSize.height()>>8) & 0xFF;
|
||||
size[3] = m_winSize.height() & 0xFF;
|
||||
sendSB(TELOPT_NAWS, size, 4);
|
||||
}
|
||||
}
|
||||
|
||||
// Handle an incoming IAC SB type chars IAC SE
|
||||
void QTelnet::handleSB()
|
||||
{
|
||||
switch( m_actualSB )
|
||||
{
|
||||
case TELOPT_TTYPE:
|
||||
if( (m_buffSB.count() > 0) && ((unsigned char)m_buffSB[0] == (unsigned char)TELQUAL_SEND) )
|
||||
{
|
||||
QTcpSocket::write(IACSB, 2);
|
||||
write(TELOPT_TTYPE);
|
||||
write(TELQUAL_IS);
|
||||
/* FIXME: need more logic here if we use
|
||||
* more than one terminal type
|
||||
*/
|
||||
QTcpSocket::write("SiraggaTerminal", 15);
|
||||
QTcpSocket::write(IACSE, 2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Analiza el texto saliente para que cumpla las normas del protocolo.
|
||||
// Además ya lo escribe en el socket.
|
||||
void QTelnet::transpose(const char *buf, int iLen)
|
||||
{
|
||||
for( int i = 0; i < iLen; i++ )
|
||||
{
|
||||
switch( buf[i] )
|
||||
{
|
||||
case IAC:
|
||||
// Escape IAC twice in stream ... to be telnet protocol compliant
|
||||
// this is there in binary and non-binary mode.
|
||||
write(IAC);
|
||||
write(IAC);
|
||||
break;
|
||||
case 10: // \n
|
||||
// We need to heed RFC 854. LF (\n) is 10, CR (\r) is 13
|
||||
// we assume that the Terminal sends \n for lf+cr and \r for just cr
|
||||
// linefeed+carriage return is CR LF
|
||||
|
||||
// En modo binario no se traduce nada.
|
||||
if( testBinaryMode() )
|
||||
write(buf[i]);
|
||||
else
|
||||
writeCustomCRLF();
|
||||
break;
|
||||
case 13: // \r
|
||||
// carriage return is CR NUL */
|
||||
|
||||
// En modo binario no se traduce nada.
|
||||
if( testBinaryMode() )
|
||||
write(buf[i]);
|
||||
else
|
||||
writeCustomCR();
|
||||
break;
|
||||
default:
|
||||
// all other characters are just copied
|
||||
write(buf[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QTelnet::willsReply(char action, char reply)
|
||||
{
|
||||
if( (reply != m_sentDX[(unsigned char)action]) || (WILL != m_receivedWX[(unsigned char)action]) )
|
||||
{
|
||||
write(IAC);
|
||||
write(reply);
|
||||
write(action);
|
||||
|
||||
m_sentDX[(unsigned char)action] = reply;
|
||||
m_receivedWX[(unsigned char)action] = WILL;
|
||||
}
|
||||
}
|
||||
|
||||
void QTelnet::wontsReply(char action, char reply)
|
||||
{
|
||||
if( (reply != m_sentDX[(unsigned char)action]) || (WONT != m_receivedWX[(unsigned char)action]) )
|
||||
{
|
||||
write(IAC);
|
||||
write(reply);
|
||||
write(action);
|
||||
|
||||
m_sentDX[(unsigned char)action] = reply;
|
||||
m_receivedWX[(unsigned char)action] = WONT;
|
||||
}
|
||||
}
|
||||
|
||||
void QTelnet::doesReply(char action, char reply)
|
||||
{
|
||||
if( (reply != m_sentWX[(unsigned char)action]) || (DO != m_receivedDX[(unsigned char)action]) )
|
||||
{
|
||||
write(IAC);
|
||||
write(reply);
|
||||
write(action);
|
||||
|
||||
m_sentWX[(unsigned char)action] = reply;
|
||||
m_receivedDX[(unsigned char)action] = DO;
|
||||
}
|
||||
}
|
||||
|
||||
void QTelnet::dontsReply(char action, char reply)
|
||||
{
|
||||
if( (reply != m_sentWX[(unsigned char)action]) || (DONT != m_receivedDX[(unsigned char)action]) )
|
||||
{
|
||||
write(IAC);
|
||||
write(reply);
|
||||
write(action);
|
||||
|
||||
m_sentWX[(unsigned char)action] = reply;
|
||||
m_receivedDX[(unsigned char)action] = DONT;
|
||||
}
|
||||
}
|
||||
|
||||
// Analiza el buffer de entrada colocá ndolo en el buffer de procesado usando el protocolo telnet.
|
||||
qint64 QTelnet::doTelnetInProtocol(qint64 buffSize)
|
||||
{
|
||||
qint64 iIn, iOut;
|
||||
char b;
|
||||
|
||||
for( iIn = 0, iOut = 0; iIn < buffSize; iIn++ )
|
||||
{
|
||||
b = m_buffIncoming[iIn];
|
||||
|
||||
switch( m_negotiationState )
|
||||
{
|
||||
case STATE_DATA:
|
||||
switch( b )
|
||||
{
|
||||
case IAC:
|
||||
m_negotiationState = STATE_IAC;
|
||||
break;
|
||||
case '\r':
|
||||
m_negotiationState = STATE_DATAR;
|
||||
break;
|
||||
case '\n':
|
||||
m_negotiationState = STATE_DATAN;
|
||||
break;
|
||||
default:
|
||||
m_buffProcessed[iOut++] = b;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case STATE_DATAN:
|
||||
case STATE_DATAR:
|
||||
switch( b )
|
||||
{
|
||||
case IAC:
|
||||
m_negotiationState = STATE_IAC;
|
||||
break;
|
||||
case '\r':
|
||||
case '\n':
|
||||
m_buffProcessed[iOut++] = '\n';
|
||||
m_negotiationState = STATE_DATA;
|
||||
break;
|
||||
default:
|
||||
m_buffProcessed[iOut++] = b;
|
||||
m_negotiationState = STATE_DATA;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case STATE_IAC:
|
||||
switch( b )
|
||||
{
|
||||
case IAC: // Dos IAC seguidos, se intenta enviar un caracter con el valor IAC.
|
||||
m_negotiationState = STATE_DATA;
|
||||
m_buffProcessed[iOut++] = IAC;
|
||||
break;
|
||||
case WILL:
|
||||
m_negotiationState = STATE_IACWILL;
|
||||
break;
|
||||
case WONT:
|
||||
m_negotiationState = STATE_IACWONT;
|
||||
break;
|
||||
case DONT:
|
||||
m_negotiationState = STATE_IACDONT;
|
||||
break;
|
||||
case DO:
|
||||
m_negotiationState = STATE_IACDO;
|
||||
break;
|
||||
case EOR:
|
||||
emitEndOfRecord();
|
||||
m_negotiationState = STATE_DATA;
|
||||
break;
|
||||
case SB:
|
||||
m_negotiationState = STATE_IACSB;
|
||||
m_buffSB.clear();
|
||||
break;
|
||||
default:
|
||||
m_negotiationState = STATE_DATA;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case STATE_IACWILL:
|
||||
switch( b )
|
||||
{
|
||||
case TELOPT_ECHO:
|
||||
emitEchoLocal(false);
|
||||
willsReply(b, DO);
|
||||
break;
|
||||
case TELOPT_SGA:
|
||||
willsReply(b, DO);
|
||||
break;
|
||||
case TELOPT_EOR:
|
||||
willsReply(b, DO);
|
||||
break;
|
||||
case TELOPT_BINARY:
|
||||
willsReply(b, DO);
|
||||
break;
|
||||
default:
|
||||
willsReply(b, DONT);
|
||||
break;
|
||||
}
|
||||
m_negotiationState = STATE_DATA;
|
||||
break;
|
||||
case STATE_IACWONT:
|
||||
switch(b)
|
||||
{
|
||||
case TELOPT_ECHO:
|
||||
emitEchoLocal(true);
|
||||
wontsReply(b, DONT);
|
||||
break;
|
||||
case TELOPT_SGA:
|
||||
wontsReply(b, DONT);
|
||||
break;
|
||||
case TELOPT_EOR:
|
||||
wontsReply(b, DONT);
|
||||
break;
|
||||
case TELOPT_BINARY:
|
||||
wontsReply(b, DONT);
|
||||
break;
|
||||
default:
|
||||
wontsReply(b, DONT);
|
||||
break;
|
||||
}
|
||||
m_negotiationState = STATE_DATA;
|
||||
break;
|
||||
case STATE_IACDO:
|
||||
switch( b )
|
||||
{
|
||||
case TELOPT_ECHO:
|
||||
doesReply(b, WILL);
|
||||
emitEchoLocal(true);
|
||||
break;
|
||||
case TELOPT_SGA:
|
||||
doesReply(b, WILL);
|
||||
break;
|
||||
case TELOPT_TTYPE:
|
||||
doesReply(b, WILL);
|
||||
break;
|
||||
case TELOPT_BINARY:
|
||||
doesReply(b, WILL);
|
||||
break;
|
||||
case TELOPT_NAWS:
|
||||
m_receivedDX[(unsigned char)b] = (unsigned char)DO;
|
||||
m_sentWX[(unsigned char)b] = (unsigned char)WILL;
|
||||
write(IAC);
|
||||
write(WILL);
|
||||
write(b);
|
||||
|
||||
// Enviamos el tamaño de la pantalla.
|
||||
sendWindowSize();
|
||||
break;
|
||||
default:
|
||||
doesReply(b, WONT);
|
||||
break;
|
||||
}
|
||||
m_negotiationState = STATE_DATA;
|
||||
break;
|
||||
case STATE_IACDONT:
|
||||
switch (b)
|
||||
{
|
||||
case TELOPT_ECHO:
|
||||
dontsReply(b, WONT);
|
||||
emitEchoLocal(false);
|
||||
break;
|
||||
case TELOPT_SGA:
|
||||
dontsReply(b, WONT);
|
||||
break;
|
||||
case TELOPT_NAWS:
|
||||
dontsReply(b, WONT);
|
||||
break;
|
||||
case TELOPT_BINARY:
|
||||
dontsReply(b, WONT);
|
||||
break;
|
||||
default:
|
||||
dontsReply(b, WONT);
|
||||
break;
|
||||
}
|
||||
m_negotiationState = STATE_DATA;
|
||||
break;
|
||||
case STATE_IACSB:
|
||||
switch( b )
|
||||
{
|
||||
case IAC:
|
||||
// Entramos en estado IAC en la sub-negociación.
|
||||
m_negotiationState = STATE_IACSBIAC;
|
||||
break;
|
||||
default:
|
||||
// Iniciamos la sub-negociación.
|
||||
m_buffSB.clear();
|
||||
m_actualSB = b;
|
||||
m_negotiationState = STATE_IACSBDATA;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case STATE_IACSBDATA: // Estamos en datos de la subnegociación.
|
||||
switch( b )
|
||||
{
|
||||
case IAC:
|
||||
m_negotiationState = STATE_IACSBDATAIAC;
|
||||
break;
|
||||
default:
|
||||
m_buffSB.append(b);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case STATE_IACSBIAC:
|
||||
switch( b )
|
||||
{
|
||||
case IAC:
|
||||
// Reiniciamos la sub-negociación.
|
||||
m_buffSB.clear();
|
||||
m_actualSB = b;
|
||||
m_negotiationState = STATE_IACSBDATA;
|
||||
default:
|
||||
// Salimos de la sub-negociación.
|
||||
m_negotiationState = STATE_DATA;
|
||||
}
|
||||
break;
|
||||
case STATE_IACSBDATAIAC:
|
||||
switch( b )
|
||||
{
|
||||
case IAC:
|
||||
m_negotiationState = STATE_IACSBDATA;
|
||||
m_buffSB.append(IAC);
|
||||
break;
|
||||
case SE:
|
||||
handleSB();
|
||||
m_actualSB = 0;
|
||||
m_buffSB.clear();
|
||||
m_negotiationState = STATE_DATA;
|
||||
break;
|
||||
case SB:
|
||||
handleSB();
|
||||
m_buffSB.clear();
|
||||
m_negotiationState = STATE_IACSB;
|
||||
break;
|
||||
default:
|
||||
m_buffSB.clear();
|
||||
m_actualSB = 0;
|
||||
m_negotiationState = STATE_DATA;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
m_negotiationState = STATE_DATA;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return iOut;
|
||||
}
|
||||
|
||||
void QTelnet::onReadyRead()
|
||||
{
|
||||
qint64 readed;
|
||||
qint64 processed;
|
||||
|
||||
while( (readed = read(m_buffIncoming, IncommingBufferSize)) != 0 )
|
||||
{
|
||||
switch( readed )
|
||||
{
|
||||
case -1:
|
||||
disconnectFromHost();
|
||||
break;
|
||||
default:
|
||||
processed = doTelnetInProtocol(readed);
|
||||
if( processed > 0 )
|
||||
Q_EMIT(newData(m_buffProcessed, processed));
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
136
src/QTelnet.h
136
src/QTelnet.h
@@ -1,136 +0,0 @@
|
||||
#ifndef QTELNET_H
|
||||
#define QTELNET_H
|
||||
|
||||
#include <QObject>
|
||||
#include <qtcpsocket.h>
|
||||
#include <qsize.h>
|
||||
#include <QString>
|
||||
|
||||
#define IncommingBufferSize (1500)
|
||||
|
||||
class QTelnet : public QTcpSocket
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum SocketStatus
|
||||
{
|
||||
Disconnected,
|
||||
Resolving, // Resolving host
|
||||
Connecting, // Connecting to host.
|
||||
Connected // Connected to host.
|
||||
};
|
||||
|
||||
protected:
|
||||
enum TelnetStateCodes
|
||||
{
|
||||
STATE_DATA = (char)0,
|
||||
STATE_IAC = (char)1,
|
||||
STATE_IACSB = (char)2,
|
||||
STATE_IACWILL = (char)3,
|
||||
STATE_IACDO = (char)4,
|
||||
STATE_IACWONT = (char)5,
|
||||
STATE_IACDONT = (char)6,
|
||||
STATE_IACSBIAC = (char)7,
|
||||
STATE_IACSBDATA = (char)8,
|
||||
STATE_IACSBDATAIAC = (char)9,
|
||||
STATE_DATAR = (char)10,
|
||||
STATE_DATAN = (char)11
|
||||
};
|
||||
enum TelnetCodes
|
||||
{
|
||||
// Negociación entrada/salida (cliente<->servidor)
|
||||
IAC = (char)255, // Inicia la secuencia para la negociación telnet.
|
||||
EOR = (char)239, // Estando en la negociación, End Of Record.
|
||||
WILL = (char)251, // Estando en la negociación, Acepta el protocolo?
|
||||
WONT = (char)252, // Estando en la negociación, Acepta el protocolo?
|
||||
DO = (char)253, // Estando en la negociación, Protocolo aceptado.
|
||||
DONT = (char)254, // Estando en la negociación, Protocolo denegado.
|
||||
SB = (char)250, // Estando en la negociación, inicia secuencia de sub-negociación.
|
||||
SE = (char)240, // Estando en la sub-negociación, fin de sub-negociación.
|
||||
|
||||
// Negociación de salida (cliente->servidor)
|
||||
TELOPT_BINARY = (char)0, // Estando en la negociación, pide modo binario.
|
||||
TELOPT_ECHO = (char)1, // Estando en la negociación, pide echo local.
|
||||
TELOPT_SGA = (char)2, // Estando en la negociación, pide Supress Go Ahead.
|
||||
TELOPT_EOR = (char)25, // Estando en la negociación, informa End Of Record.
|
||||
TELOPT_NAWS = (char)31, // Estando en la negociación, Negotiate Abaut Window Size.
|
||||
TELOPT_TTYPE = (char)24 // Estando en la negociación, Terminal Type.
|
||||
};
|
||||
enum TelnetQualifiers
|
||||
{
|
||||
TELQUAL_IS = (char)0,
|
||||
TELQUAL_SEND = (char)1
|
||||
};
|
||||
|
||||
private:
|
||||
static const char IACWILL[2];
|
||||
static const char IACWONT[2];
|
||||
static const char IACDO[2];
|
||||
static const char IACDONT[2];
|
||||
static const char IACSB[2];
|
||||
static const char IACSE[2];
|
||||
static char _sendCodeArray[2];
|
||||
static char _arrCRLF[2];
|
||||
static char _arrCR[2];
|
||||
|
||||
QSize m_winSize; // Tamaño de la pantalla en caracteres.
|
||||
QSize m_oldWinSize; // Tamaño de la pantalla que se envió por última vez al server. Para no enviar el mismo dato.
|
||||
enum TelnetStateCodes m_negotiationState;
|
||||
char m_receivedDX[256]; // What IAC DO(NT) request do we have received already ?
|
||||
char m_receivedWX[256]; // What IAC WILL/WONT request do we have received already ?
|
||||
char m_sentDX[256]; // What IAC DO/DONT request do we have sent already ?
|
||||
char m_sentWX[256]; // What IAC WILL/WONT request do we have sent already ?
|
||||
void resetProtocol();
|
||||
|
||||
char m_buffIncoming[IncommingBufferSize];
|
||||
char m_buffProcessed[IncommingBufferSize];
|
||||
QByteArray m_buffSB;
|
||||
int m_actualSB;
|
||||
|
||||
void emitEndOfRecord() { Q_EMIT(endOfRecord()); }
|
||||
void emitEchoLocal(bool bEcho) { Q_EMIT(echoLocal(bEcho)); }
|
||||
|
||||
void sendTelnetControl(char codigo);
|
||||
void handleSB(void);
|
||||
void transpose(const char *buf, int iLen);
|
||||
|
||||
void willsReply(char action, char reply);
|
||||
void wontsReply(char action, char reply);
|
||||
void doesReply(char action, char reply);
|
||||
void dontsReply(char action, char reply);
|
||||
|
||||
void sendSB(char code, char *arr, int iLen);
|
||||
qint64 doTelnetInProtocol(qint64 buffSize);
|
||||
|
||||
public:
|
||||
explicit QTelnet(QObject *parent = 0);
|
||||
|
||||
virtual void connectToHost(const QString &host, quint16 port);
|
||||
void sendData(const QByteArray &ba);
|
||||
void setCustomCRLF(char lf = 13, char cr = 10);
|
||||
void setCustomCR(char cr = 10, char cr2 = 0);
|
||||
|
||||
void writeCustomCRLF();
|
||||
void writeCustomCR();
|
||||
|
||||
void write(const char c);
|
||||
|
||||
bool isConnected() const;
|
||||
bool testBinaryMode() const;
|
||||
void setWindSize(QSize s) {m_winSize = s;}
|
||||
void sendWindowSize();
|
||||
|
||||
QString peerInfo()const;
|
||||
|
||||
signals:
|
||||
void newData(const char *buff, int len);
|
||||
void endOfRecord();
|
||||
void echoLocal(bool echo);
|
||||
|
||||
private slots:
|
||||
void socketError(QAbstractSocket::SocketError err);
|
||||
void onReadyRead();
|
||||
};
|
||||
|
||||
#endif // QTELNET_H
|
||||
@@ -93,7 +93,7 @@ Item {
|
||||
onLinkActivated: Qt.openUrlExternally(link)
|
||||
}
|
||||
|
||||
Button {
|
||||
/*Button {
|
||||
id: restoreButton
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
@@ -101,8 +101,7 @@ Item {
|
||||
text: "Restore Purchases"
|
||||
onClicked: {
|
||||
console.log("restoring...");
|
||||
toast.show("Restoring...");
|
||||
iapStore.restorePurchases();
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ import Qt.labs.settings 1.0
|
||||
|
||||
ColumnLayout {
|
||||
signal trainprogram_open_clicked(url name)
|
||||
signal trainprogram_open_other_folder(url name)
|
||||
signal trainprogram_preview(url name)
|
||||
FileDialog {
|
||||
id: fileDialogTrainProgram
|
||||
@@ -17,11 +16,7 @@ ColumnLayout {
|
||||
folder: shortcuts.home
|
||||
onAccepted: {
|
||||
console.log("You chose: " + fileDialogTrainProgram.fileUrl)
|
||||
if(OS_VERSION === "Android") {
|
||||
trainprogram_open_other_folder(fileDialogTrainProgram.fileUrl)
|
||||
} else {
|
||||
trainprogram_open_clicked(fileDialogTrainProgram.fileUrl)
|
||||
}
|
||||
trainprogram_open_clicked(fileDialogTrainProgram.fileUrl)
|
||||
fileDialogTrainProgram.close()
|
||||
}
|
||||
onRejected: {
|
||||
|
||||
@@ -297,7 +297,6 @@ void activiotreadmill::characteristicChanged(const QLowEnergyCharacteristic &cha
|
||||
settings.value(QZSettings::heart_rate_belt_name, QZSettings::default_heart_rate_belt_name).toString();
|
||||
Q_UNUSED(characteristic);
|
||||
QByteArray value = newValue;
|
||||
QDateTime now = QDateTime::currentDateTime();
|
||||
|
||||
emit debug(QStringLiteral(" << ") + QString::number(value.length()) + QStringLiteral(" ") + value.toHex(' '));
|
||||
emit packetReceived();
|
||||
@@ -340,12 +339,12 @@ void activiotreadmill::characteristicChanged(const QLowEnergyCharacteristic &cha
|
||||
settings.value(QZSettings::weight, QZSettings::default_weight).toFloat() * 3.5) /
|
||||
200.0) /
|
||||
(60000.0 / ((double)lastTimeCharacteristicChanged.msecsTo(
|
||||
now)))); //(( (0.048* Output in watts +1.19) * body weight in
|
||||
QDateTime::currentDateTime())))); //(( (0.048* Output in watts +1.19) * body weight in
|
||||
// kg * 3.5) / 200 ) / 60
|
||||
|
||||
Distance += ((speed / (double)3600.0) /
|
||||
((double)1000.0 / (double)(lastTimeCharacteristicChanged.msecsTo(now))));
|
||||
lastTimeCharacteristicChanged = now;
|
||||
((double)1000.0 / (double)(lastTimeCharacteristicChanged.msecsTo(QDateTime::currentDateTime()))));
|
||||
lastTimeCharacteristicChanged = QDateTime::currentDateTime();
|
||||
}
|
||||
|
||||
emit debug(QStringLiteral("Current speed: ") + QString::number(speed));
|
||||
|
||||
@@ -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.16.29" android:versionCode="693" 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.98" android:versionCode="614" android:installLocation="auto">
|
||||
<!-- The following comment will be replaced upon deployment with default permissions based on the dependencies of the application.
|
||||
Remove the comment if you do not require these default permissions. -->
|
||||
<!-- %%INSERT_PERMISSIONS -->
|
||||
@@ -79,19 +79,6 @@
|
||||
android:name=".ForegroundService"
|
||||
android:enabled="true"
|
||||
android:exported="true"></service>
|
||||
<service
|
||||
android:name=".WearableMessageListenerService"
|
||||
android:enabled="true"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="com.google.android.gms.wearable.MESSAGE_RECEIVED" />
|
||||
<action android:name="com.google.android.gms.wearable.DATA_CHANGED" />
|
||||
<data
|
||||
android:host="*"
|
||||
android:pathPrefix="/qz"
|
||||
android:scheme="wear" />
|
||||
</intent-filter>
|
||||
</service>
|
||||
<service android:name=".ChannelService"></service>
|
||||
<service android:name=".FloatingWindowGFG" android:enabled="true" android:exported="true"/>
|
||||
|
||||
|
||||
BIN
src/android/assets/models/ch_PP-OCRv2/cls.pdiparams
Normal file
BIN
src/android/assets/models/ch_PP-OCRv2/cls.pdiparams
Normal file
Binary file not shown.
BIN
src/android/assets/models/ch_PP-OCRv2/cls.pdmodel
Normal file
BIN
src/android/assets/models/ch_PP-OCRv2/cls.pdmodel
Normal file
Binary file not shown.
BIN
src/android/assets/models/ch_PP-OCRv2/det.pdiparams
Normal file
BIN
src/android/assets/models/ch_PP-OCRv2/det.pdiparams
Normal file
Binary file not shown.
BIN
src/android/assets/models/ch_PP-OCRv2/det.pdmodel
Normal file
BIN
src/android/assets/models/ch_PP-OCRv2/det.pdmodel
Normal file
Binary file not shown.
95
src/android/assets/models/ch_PP-OCRv2/ppocr_keys_v1.txt
Normal file
95
src/android/assets/models/ch_PP-OCRv2/ppocr_keys_v1.txt
Normal file
@@ -0,0 +1,95 @@
|
||||
0
|
||||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
5
|
||||
6
|
||||
7
|
||||
8
|
||||
9
|
||||
:
|
||||
;
|
||||
<
|
||||
=
|
||||
>
|
||||
?
|
||||
@
|
||||
A
|
||||
B
|
||||
C
|
||||
D
|
||||
E
|
||||
F
|
||||
G
|
||||
H
|
||||
I
|
||||
J
|
||||
K
|
||||
L
|
||||
M
|
||||
N
|
||||
O
|
||||
P
|
||||
Q
|
||||
R
|
||||
S
|
||||
T
|
||||
U
|
||||
V
|
||||
W
|
||||
X
|
||||
Y
|
||||
Z
|
||||
[
|
||||
\
|
||||
]
|
||||
^
|
||||
_
|
||||
`
|
||||
a
|
||||
b
|
||||
c
|
||||
d
|
||||
e
|
||||
f
|
||||
g
|
||||
h
|
||||
i
|
||||
j
|
||||
k
|
||||
l
|
||||
m
|
||||
n
|
||||
o
|
||||
p
|
||||
q
|
||||
r
|
||||
s
|
||||
t
|
||||
u
|
||||
v
|
||||
w
|
||||
x
|
||||
y
|
||||
z
|
||||
{
|
||||
|
|
||||
}
|
||||
~
|
||||
!
|
||||
"
|
||||
#
|
||||
$
|
||||
%
|
||||
&
|
||||
'
|
||||
(
|
||||
)
|
||||
*
|
||||
+
|
||||
,
|
||||
-
|
||||
.
|
||||
/
|
||||
|
||||
BIN
src/android/assets/models/ch_PP-OCRv2/rec.pdiparams
Normal file
BIN
src/android/assets/models/ch_PP-OCRv2/rec.pdiparams
Normal file
Binary file not shown.
BIN
src/android/assets/models/ch_PP-OCRv2/rec.pdmodel
Normal file
BIN
src/android/assets/models/ch_PP-OCRv2/rec.pdmodel
Normal file
Binary file not shown.
@@ -23,7 +23,7 @@ println(amazon)
|
||||
|
||||
dependencies {
|
||||
compile 'com.rvalerio:fgchecker:1.1.0'
|
||||
implementation "androidx.core:core-ktx:1.12.0"
|
||||
implementation "androidx.core:core-ktx:+"
|
||||
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.1.0"
|
||||
|
||||
if(amazon == "1") {
|
||||
@@ -33,6 +33,7 @@ dependencies {
|
||||
// google play store
|
||||
implementation 'com.google.android.gms:play-services-mlkit-text-recognition:18.0.2'
|
||||
}
|
||||
implementation 'com.github.cagnulein:paddleocr4android:1.2.8e-sdk21'
|
||||
|
||||
implementation 'com.google.android.play:core:1.8.2'
|
||||
|
||||
@@ -46,7 +47,6 @@ dependencies {
|
||||
implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
|
||||
implementation 'com.github.mik3y:usb-serial-for-android:v3.4.6'
|
||||
androidTestImplementation "com.android.support:support-annotations:28.0.0"
|
||||
implementation 'com.google.android.gms:play-services-wearable:+'
|
||||
}
|
||||
|
||||
android {
|
||||
@@ -100,6 +100,17 @@ android {
|
||||
compileSdkVersion 33
|
||||
minSdkVersion = 21
|
||||
targetSdkVersion = 33
|
||||
|
||||
externalNativeBuild {
|
||||
cmake {
|
||||
cppFlags "-std=c++11 -frtti -fexceptions -Wno-format"
|
||||
arguments '-DANDROID_PLATFORM=android-21', '-DANDROID_STL=c++_shared' ,"-DANDROID_ARM_NEON=TRUE"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
packagingOptions {
|
||||
exclude 'META-INF/kotlinx_coroutines_core.version'
|
||||
}
|
||||
|
||||
tasks.all { task ->
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
|
||||
<!-- Concept2 PM3,PM4 -->
|
||||
<usb-device vendor-id="17A4" product-id="0002" />
|
||||
<usb-device vendor-id="17A4" product-id="0001" />
|
||||
|
||||
<!-- CDC driver -->
|
||||
<usb-device vendor-id="9025" /> <!-- 0x2341 / ......: Arduino -->
|
||||
|
||||
@@ -35,13 +35,11 @@ public class Ant {
|
||||
static boolean speedRequest = false;
|
||||
static boolean heartRequest = false;
|
||||
static boolean garminKey = false;
|
||||
static boolean treadmill = false;
|
||||
|
||||
public void antStart(Activity a, boolean SpeedRequest, boolean HeartRequest, boolean GarminKey, boolean Treadmill) {
|
||||
public void antStart(Activity a, boolean SpeedRequest, boolean HeartRequest, boolean GarminKey) {
|
||||
Log.v(TAG, "antStart");
|
||||
speedRequest = SpeedRequest;
|
||||
heartRequest = HeartRequest;
|
||||
treadmill = Treadmill;
|
||||
garminKey = GarminKey;
|
||||
|
||||
activity = a;
|
||||
|
||||
@@ -35,14 +35,9 @@ public class CSafeRowerUSBHID {
|
||||
|
||||
public static void open(Context context) {
|
||||
Log.d("QZ","CSafeRowerUSBHID open");
|
||||
hidBridge = new HidBridge(context, 0x0002, 0x17A4);
|
||||
hidBridge = new HidBridge(context, 0x0002, 0x17A4);
|
||||
boolean ret = hidBridge.OpenDevice();
|
||||
Log.d("QZ","hidBridge.OpenDevice " + ret);
|
||||
if(ret == false) {
|
||||
hidBridge = new HidBridge(context, 0x0001, 0x17A4);
|
||||
ret = hidBridge.OpenDevice();
|
||||
Log.d("QZ","hidBridge.OpenDevice " + ret);
|
||||
}
|
||||
hidBridge.StartReadingThread();
|
||||
Log.d("QZ","hidBridge.StartReadingThread");
|
||||
}
|
||||
|
||||
@@ -50,7 +50,6 @@ public class ChannelService extends Service {
|
||||
HeartChannelController heartChannelController = null;
|
||||
PowerChannelController powerChannelController = null;
|
||||
SpeedChannelController speedChannelController = null;
|
||||
SDMChannelController sdmChannelController = null;
|
||||
|
||||
private ServiceConnection mAntRadioServiceConnection = new ServiceConnection() {
|
||||
@Override
|
||||
@@ -105,9 +104,6 @@ public class ChannelService extends Service {
|
||||
if (null != speedChannelController) {
|
||||
speedChannelController.speed = speed;
|
||||
}
|
||||
if (null != sdmChannelController) {
|
||||
sdmChannelController.speed = speed;
|
||||
}
|
||||
}
|
||||
|
||||
void setPower(int power) {
|
||||
@@ -123,9 +119,6 @@ public class ChannelService extends Service {
|
||||
if (null != speedChannelController) {
|
||||
speedChannelController.cadence = cadence;
|
||||
}
|
||||
if (null != sdmChannelController) {
|
||||
sdmChannelController.cadence = cadence;
|
||||
}
|
||||
}
|
||||
|
||||
int getHeart() {
|
||||
@@ -148,12 +141,8 @@ public class ChannelService extends Service {
|
||||
heartChannelController = new HeartChannelController(acquireChannel());
|
||||
|
||||
if (Ant.speedRequest) {
|
||||
if(Ant.treadmill) {
|
||||
sdmChannelController = new SDMChannelController(acquireChannel());
|
||||
} else {
|
||||
powerChannelController = new PowerChannelController(acquireChannel());
|
||||
speedChannelController = new SpeedChannelController(acquireChannel());
|
||||
}
|
||||
powerChannelController = new PowerChannelController(acquireChannel());
|
||||
speedChannelController = new SpeedChannelController(acquireChannel());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,12 +153,9 @@ public class ChannelService extends Service {
|
||||
powerChannelController.close();
|
||||
if (speedChannelController != null)
|
||||
speedChannelController.close();
|
||||
if (sdmChannelController != null)
|
||||
sdmChannelController.close();
|
||||
heartChannelController = null;
|
||||
powerChannelController = null;
|
||||
speedChannelController = null;
|
||||
sdmChannelController = null;
|
||||
}
|
||||
|
||||
AntChannel acquireChannel() throws ChannelNotAvailableException {
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
package org.cagnulen.qdomyoszwift;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.net.Uri;
|
||||
import android.provider.OpenableColumns;
|
||||
import android.util.Log;
|
||||
|
||||
public class ContentHelper {
|
||||
|
||||
public static String getFileName(Context context, Uri uri) {
|
||||
String result = null;
|
||||
if (uri.getScheme().equals("content")) {
|
||||
Log.d("ContentHelper", "content");
|
||||
Cursor cursor = context.getContentResolver().query(uri, null, null, null, null);
|
||||
Log.d("ContentHelper", "cursor " + cursor);
|
||||
try {
|
||||
if (cursor != null && cursor.moveToFirst()) {
|
||||
result = cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
|
||||
Log.d("ContentHelper", "result " + result);
|
||||
}
|
||||
} finally {
|
||||
cursor.close();
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -49,9 +49,6 @@ public class QZAdbRemote implements DeviceConnectionListener {
|
||||
|
||||
private static QZAdbRemote INSTANCE;
|
||||
|
||||
private static String receiveBuffer = "";
|
||||
private static String receiveOldBuffer = "";
|
||||
|
||||
public static QZAdbRemote getInstance() {
|
||||
if(INSTANCE == null) {
|
||||
INSTANCE = new QZAdbRemote();
|
||||
@@ -96,6 +93,7 @@ public class QZAdbRemote implements DeviceConnectionListener {
|
||||
|
||||
@Override
|
||||
public void receivedData(DeviceConnection devConn, byte[] data, int offset, int length) {
|
||||
Log.i(LOG_TAG, data.toString());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -105,8 +103,7 @@ public class QZAdbRemote implements DeviceConnectionListener {
|
||||
|
||||
@Override
|
||||
public void consoleUpdated(DeviceConnection devConn, ConsoleBuffer console) {
|
||||
receiveBuffer += new String(console.buffer);
|
||||
Log.i(LOG_TAG, new String(console.buffer));
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -198,12 +195,6 @@ public class QZAdbRemote implements DeviceConnectionListener {
|
||||
}
|
||||
}
|
||||
|
||||
static public String getReceiveData() {
|
||||
receiveOldBuffer = receiveBuffer;
|
||||
receiveBuffer = "";
|
||||
return receiveOldBuffer;
|
||||
}
|
||||
|
||||
static public void sendCommand(String command) {
|
||||
Log.d(LOG_TAG, "sendCommand " + ADBConnected + " " + command);
|
||||
if(ADBConnected) {
|
||||
|
||||
@@ -1,308 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012 Dynastream Innovations Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy of
|
||||
* the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*/
|
||||
package org.cagnulen.qdomyoszwift;
|
||||
|
||||
import android.os.RemoteException;
|
||||
import android.os.SystemClock;
|
||||
import android.util.Log;
|
||||
|
||||
import com.dsi.ant.channel.AntChannel;
|
||||
import com.dsi.ant.channel.AntCommandFailedException;
|
||||
import com.dsi.ant.channel.IAntChannelEventHandler;
|
||||
import com.dsi.ant.message.ChannelId;
|
||||
import com.dsi.ant.message.ChannelType;
|
||||
import com.dsi.ant.message.EventCode;
|
||||
import com.dsi.ant.message.fromant.ChannelEventMessage;
|
||||
import com.dsi.ant.message.fromant.MessageFromAntType;
|
||||
import com.dsi.ant.message.ipc.AntMessageParcel;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
public class SDMChannelController {
|
||||
// The device type and transmission type to be part of the channel ID message
|
||||
private static final int CHANNEL_SPEED_DEVICE_TYPE = 0x7C;
|
||||
private static final int CHANNEL_SPEED_TRANSMISSION_TYPE = 1;
|
||||
|
||||
// The period and frequency values the channel will be configured to
|
||||
private static final int CHANNEL_SPEED_PERIOD = 8134; // 1 Hz
|
||||
private static final int CHANNEL_SPEED_FREQUENCY = 57;
|
||||
|
||||
private static final String TAG = SDMChannelController.class.getSimpleName();
|
||||
public static final int SPEED_SENSOR_ID = 0x9e3d4b99;
|
||||
|
||||
private static final double MILLISECOND_TO_1_1024_CONVERSION = 0.9765625;
|
||||
|
||||
private AntChannel mAntChannel;
|
||||
|
||||
private ChannelEventCallback mChannelEventCallback = new ChannelEventCallback();
|
||||
|
||||
private boolean mIsOpen;
|
||||
double speed = 0.0;
|
||||
int cadence = 0;
|
||||
byte stride_count = 0;
|
||||
|
||||
public SDMChannelController(AntChannel antChannel) {
|
||||
mAntChannel = antChannel;
|
||||
openChannel();
|
||||
}
|
||||
|
||||
boolean openChannel() {
|
||||
if (null != mAntChannel) {
|
||||
if (mIsOpen) {
|
||||
Log.w(TAG, "Channel was already open");
|
||||
} else {
|
||||
// Channel ID message contains device number, type and transmission type. In
|
||||
// order for master (TX) channels and slave (RX) channels to connect, they
|
||||
// must have the same channel ID, or wildcard (0) is used.
|
||||
ChannelId channelId = new ChannelId(SPEED_SENSOR_ID & 0xFFFF,
|
||||
CHANNEL_SPEED_DEVICE_TYPE, CHANNEL_SPEED_TRANSMISSION_TYPE);
|
||||
|
||||
try {
|
||||
// Setting the channel event handler so that we can receive messages from ANT
|
||||
mAntChannel.setChannelEventHandler(mChannelEventCallback);
|
||||
|
||||
// Performs channel assignment by assigning the type to the channel. Additional
|
||||
// features (such as, background scanning and frequency agility) can be enabled
|
||||
// by passing an ExtendedAssignment object to assign(ChannelType, ExtendedAssignment).
|
||||
mAntChannel.assign(ChannelType.BIDIRECTIONAL_MASTER);
|
||||
|
||||
/*
|
||||
* Configures the channel ID, messaging period and rf frequency after assigning,
|
||||
* then opening the channel.
|
||||
*
|
||||
* For any additional ANT features such as proximity search or background scanning, refer to
|
||||
* the ANT Protocol Doc found at:
|
||||
* http://www.thisisant.com/resources/ant-message-protocol-and-usage/
|
||||
*/
|
||||
mAntChannel.setChannelId(channelId);
|
||||
mAntChannel.setPeriod(CHANNEL_SPEED_PERIOD);
|
||||
mAntChannel.setRfFrequency(CHANNEL_SPEED_FREQUENCY);
|
||||
mAntChannel.open();
|
||||
mIsOpen = true;
|
||||
|
||||
Log.d(TAG, "Opened channel with device number: " + SPEED_SENSOR_ID);
|
||||
} catch (RemoteException e) {
|
||||
channelError(e);
|
||||
} catch (AntCommandFailedException e) {
|
||||
// This will release, and therefore unassign if required
|
||||
channelError("Open failed", e);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Log.w(TAG, "No channel available");
|
||||
}
|
||||
|
||||
return mIsOpen;
|
||||
}
|
||||
|
||||
void channelError(RemoteException e) {
|
||||
String logString = "Remote service communication failed.";
|
||||
|
||||
Log.e(TAG, logString);
|
||||
}
|
||||
|
||||
void channelError(String error, AntCommandFailedException e) {
|
||||
StringBuilder logString;
|
||||
|
||||
if (e.getResponseMessage() != null) {
|
||||
String initiatingMessageId = "0x" + Integer.toHexString(
|
||||
e.getResponseMessage().getInitiatingMessageId());
|
||||
String rawResponseCode = "0x" + Integer.toHexString(
|
||||
e.getResponseMessage().getRawResponseCode());
|
||||
|
||||
logString = new StringBuilder(error)
|
||||
.append(". Command ")
|
||||
.append(initiatingMessageId)
|
||||
.append(" failed with code ")
|
||||
.append(rawResponseCode);
|
||||
} else {
|
||||
String attemptedMessageId = "0x" + Integer.toHexString(
|
||||
e.getAttemptedMessageType().getMessageId());
|
||||
String failureReason = e.getFailureReason().toString();
|
||||
|
||||
logString = new StringBuilder(error)
|
||||
.append(". Command ")
|
||||
.append(attemptedMessageId)
|
||||
.append(" failed with reason ")
|
||||
.append(failureReason);
|
||||
}
|
||||
|
||||
Log.e(TAG, logString.toString());
|
||||
|
||||
mAntChannel.release();
|
||||
|
||||
Log.e(TAG, "ANT Command Failed");
|
||||
}
|
||||
|
||||
public void close() {
|
||||
// TODO kill all our resources
|
||||
if (null != mAntChannel) {
|
||||
mIsOpen = false;
|
||||
|
||||
// Releasing the channel to make it available for others.
|
||||
// After releasing, the AntChannel instance cannot be reused.
|
||||
mAntChannel.release();
|
||||
mAntChannel = null;
|
||||
}
|
||||
|
||||
Log.e(TAG, "Channel Closed");
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements the Channel Event Handler Interface so that messages can be
|
||||
* received and channel death events can be handled.
|
||||
*/
|
||||
public class ChannelEventCallback implements IAntChannelEventHandler {
|
||||
long lastTime = 0;
|
||||
double totalWay = 0.0;
|
||||
double totalRotations = 0.0;
|
||||
long lastSpeedEventTime = 0;
|
||||
long lastCadenceEventTime = 0;
|
||||
long elapsedMillis = 0;
|
||||
int rotations;
|
||||
int rev;
|
||||
double wheel = 0.1;
|
||||
Timer carousalTimer = null;
|
||||
|
||||
@Override
|
||||
public void onChannelDeath() {
|
||||
// Display channel death message when channel dies
|
||||
Log.e(TAG, "Channel Death");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceiveMessage(MessageFromAntType messageType, AntMessageParcel antParcel) {
|
||||
Log.d(TAG, "Rx: " + antParcel);
|
||||
Log.d(TAG, "Message Type: " + messageType);
|
||||
|
||||
if(carousalTimer == null) {
|
||||
carousalTimer = new Timer(); // At this line a new Thread will be created
|
||||
carousalTimer.scheduleAtFixedRate(new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
Log.d(TAG, "Tx Unsollicited");
|
||||
long realtimeMillis = SystemClock.elapsedRealtime();
|
||||
double speedM_s = speed / 3.6;
|
||||
long deltaTime = (realtimeMillis - lastTime);
|
||||
lastTime = realtimeMillis;
|
||||
|
||||
byte[] payload = new byte[8];
|
||||
|
||||
payload[0] = (byte) 0x01;
|
||||
payload[1] = (byte) (((lastTime % 256000) / 5) & 0xFF);
|
||||
payload[2] = (byte) ((lastTime % 256000) / 1000);
|
||||
payload[3] = (byte) 0x00;
|
||||
payload[4] = (byte) speedM_s;
|
||||
payload[5] = (byte) ((speedM_s - (double)((int)speedM_s)) / (1.0/256.0));
|
||||
payload[6] = (byte) stride_count++; // bad but it works on zwift
|
||||
payload[7] = (byte) ((double)deltaTime * 0.03125);
|
||||
|
||||
if (mIsOpen) {
|
||||
try {
|
||||
// Setting the data to be broadcast on the next channel period
|
||||
mAntChannel.setBroadcastData(payload);
|
||||
} catch (RemoteException e) {
|
||||
channelError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}, 0, 250); // delay
|
||||
}
|
||||
|
||||
// Switching on message type to handle different types of messages
|
||||
switch (messageType) {
|
||||
// If data message, construct from parcel and update channel data
|
||||
case BROADCAST_DATA:
|
||||
// Rx Data
|
||||
//updateData(new BroadcastDataMessage(antParcel).getPayload());
|
||||
break;
|
||||
case ACKNOWLEDGED_DATA:
|
||||
// Rx Data
|
||||
//updateData(new AcknowledgedDataMessage(antParcel).getPayload());
|
||||
break;
|
||||
case CHANNEL_EVENT:
|
||||
// Constructing channel event message from parcel
|
||||
ChannelEventMessage eventMessage = new ChannelEventMessage(antParcel);
|
||||
EventCode code = eventMessage.getEventCode();
|
||||
Log.d(TAG, "Event Code: " + code);
|
||||
|
||||
// Switching on event code to handle the different types of channel events
|
||||
switch (code) {
|
||||
case TX:
|
||||
long realtimeMillis = SystemClock.elapsedRealtime();
|
||||
double speedM_s = speed / 3.6;
|
||||
long deltaTime = (realtimeMillis - lastTime);
|
||||
// in case the treadmill doesn't provide cadence, I have to force it. ANT+ requires cadence
|
||||
lastTime = realtimeMillis;
|
||||
|
||||
byte[] payload = new byte[8];
|
||||
|
||||
payload[0] = (byte) 0x01;
|
||||
payload[1] = (byte) (((lastTime % 256000) / 5) & 0xFF);
|
||||
payload[2] = (byte) ((lastTime % 256000) / 1000);
|
||||
payload[3] = (byte) 0x00;
|
||||
payload[4] = (byte) speedM_s;
|
||||
payload[5] = (byte) ((speedM_s - (double)((int)speedM_s)) / (1.0/256.0));
|
||||
payload[6] = (byte) stride_count;
|
||||
payload[7] = (byte) ((double)deltaTime * 0.03125);
|
||||
|
||||
if (mIsOpen) {
|
||||
try {
|
||||
// Setting the data to be broadcast on the next channel period
|
||||
mAntChannel.setBroadcastData(payload);
|
||||
} catch (RemoteException e) {
|
||||
channelError(e);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CHANNEL_COLLISION:
|
||||
break;
|
||||
case RX_SEARCH_TIMEOUT:
|
||||
// TODO May want to keep searching
|
||||
Log.e(TAG, "No Device Found");
|
||||
break;
|
||||
case CHANNEL_CLOSED:
|
||||
case RX_FAIL:
|
||||
case RX_FAIL_GO_TO_SEARCH:
|
||||
case TRANSFER_RX_FAILED:
|
||||
case TRANSFER_TX_COMPLETED:
|
||||
case TRANSFER_TX_FAILED:
|
||||
case TRANSFER_TX_START:
|
||||
case UNKNOWN:
|
||||
// TODO More complex communication will need to handle these events
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case ANT_VERSION:
|
||||
case BURST_TRANSFER_DATA:
|
||||
case CAPABILITIES:
|
||||
case CHANNEL_ID:
|
||||
case CHANNEL_RESPONSE:
|
||||
case CHANNEL_STATUS:
|
||||
case SERIAL_NUMBER:
|
||||
case OTHER:
|
||||
// TODO More complex communication will need to handle these message types
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.hardware.display.DisplayManager;
|
||||
import android.hardware.display.VirtualDisplay;
|
||||
@@ -44,6 +45,16 @@ import android.graphics.Point;
|
||||
|
||||
import androidx.core.util.Pair;
|
||||
|
||||
import com.baidu.paddle.fastdeploy.LitePowerMode;
|
||||
import com.equationl.fastdeployocr.OCR;
|
||||
import com.equationl.fastdeployocr.OcrConfig;
|
||||
import com.equationl.fastdeployocr.RunPrecision;
|
||||
import com.equationl.fastdeployocr.RunType;
|
||||
import com.equationl.fastdeployocr.bean.OcrResult;
|
||||
import com.equationl.fastdeployocr.bean.OcrResultModel;
|
||||
import com.equationl.fastdeployocr.callback.OcrInitCallback;
|
||||
import com.equationl.fastdeployocr.callback.OcrRunCallback;
|
||||
|
||||
public class ScreenCaptureService extends Service {
|
||||
|
||||
private static final String TAG = "ScreenCaptureService";
|
||||
@@ -76,6 +87,9 @@ public class ScreenCaptureService extends Service {
|
||||
private static String lastTextExtended = "";
|
||||
private static boolean isRunning = false;
|
||||
|
||||
private OcrConfig config = new OcrConfig();
|
||||
private OCR ocr = null;
|
||||
|
||||
public static String getLastText() {
|
||||
return lastText;
|
||||
}
|
||||
@@ -141,72 +155,45 @@ public class ScreenCaptureService extends Service {
|
||||
mHeightImage = mHeight;
|
||||
final Bitmap bitmap = Bitmap.createBitmap(mWidth + rowPadding / pixelStride, mHeight, Bitmap.Config.ARGB_8888);
|
||||
bitmap.copyPixelsFromBuffer(buffer);
|
||||
/*
|
||||
|
||||
// write bitmap to a file
|
||||
fos = new FileOutputStream(mStoreDir + "/myscreen.png");
|
||||
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
|
||||
fos = new FileOutputStream(mStoreDir + "/myscreen.jpg");
|
||||
bitmap.compress(Bitmap.CompressFormat.PNG, 100, fos);
|
||||
|
||||
IMAGES_PRODUCED++;
|
||||
Log.e(TAG, "captured image: " + IMAGES_PRODUCED);
|
||||
*/
|
||||
|
||||
InputImage inputImage = InputImage.fromBitmap(bitmap, 0);
|
||||
/*InputImage inputImage = InputImage.fromByteBuffer(buffer,
|
||||
mWidth + rowPadding / pixelStride, mHeight,
|
||||
0,
|
||||
InputImage.IMAGE_FORMAT_NV21 // or IMAGE_FORMAT_YV12
|
||||
);*/
|
||||
Bitmap bMap = BitmapFactory.decodeFile(mStoreDir + "/processed_screenshot.jpg");
|
||||
|
||||
Task<Text> result =
|
||||
recognizer.process(inputImage)
|
||||
.addOnSuccessListener(new OnSuccessListener<Text>() {
|
||||
@Override
|
||||
public void onSuccess(Text result) {
|
||||
// Task completed successfully
|
||||
|
||||
//Log.e(TAG, "Image done!");
|
||||
|
||||
String resultText = result.getText();
|
||||
lastText = resultText;
|
||||
lastTextExtended = "";
|
||||
for (Text.TextBlock block : result.getTextBlocks()) {
|
||||
String blockText = block.getText();
|
||||
Point[] blockCornerPoints = block.getCornerPoints();
|
||||
Rect blockFrame = block.getBoundingBox();
|
||||
lastTextExtended = lastTextExtended + blockText + "$$" + blockFrame.toString() + "§§";
|
||||
/*for (Text.Line line : block.getLines()) {
|
||||
String lineText = line.getText();
|
||||
Point[] lineCornerPoints = line.getCornerPoints();
|
||||
Rect lineFrame = line.getBoundingBox();
|
||||
for (Text.Element element : line.getElements()) {
|
||||
String elementText = element.getText();
|
||||
Point[] elementCornerPoints = element.getCornerPoints();
|
||||
Rect elementFrame = element.getBoundingBox();
|
||||
for (Text.Symbol symbol : element.getSymbols()) {
|
||||
String symbolText = symbol.getText();
|
||||
Point[] symbolCornerPoints = symbol.getCornerPoints();
|
||||
Rect symbolFrame = symbol.getBoundingBox();
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
bitmap.recycle();
|
||||
isRunning = false;
|
||||
}
|
||||
})
|
||||
.addOnFailureListener(
|
||||
new OnFailureListener() {
|
||||
@Override
|
||||
public void onFailure(Exception e) {
|
||||
// Task failed with an exception
|
||||
//Log.e(TAG, "Image fail");
|
||||
isRunning = false;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
//Log.e(TAG, "Image ignored");
|
||||
}
|
||||
ocr.run(bMap, new OcrRunCallback() {
|
||||
@Override
|
||||
public void onSuccess(OcrResult result) {
|
||||
lastText = result.getSimpleText();
|
||||
lastTextExtended = "";
|
||||
/*
|
||||
for (int index = 0; index < result.getOutputRawResult().size(); index++) {
|
||||
OcrResultModel ocrResultModel = result.getOutputRawResult().get(index);
|
||||
// 文字方向 ocrResultModel.clsLabel 可能为 "0" 或 "180"
|
||||
lastText += ocrResultModel.getClsLabel();
|
||||
lastTextExtended += index + ": 文字方向:" + ocrResultModel.getClsLabel() +
|
||||
";文字方向置信度:" + ocrResultModel.getClsConfidenceL() +
|
||||
";识别置信度 " + ocrResultModel.getConfidence() +
|
||||
";;文字位置:" + ocrResultModel.getPoints() + "\n";
|
||||
}*/
|
||||
isRunning = false;
|
||||
bitmap.recycle();
|
||||
Log.e(TAG, "onSuccess: " + lastText);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFail(Throwable e) {
|
||||
Log.e(TAG, "onFail: 识别失败!", e);
|
||||
isRunning = false;
|
||||
bitmap.recycle();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
@@ -263,6 +250,71 @@ public class ScreenCaptureService extends Service {
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
|
||||
Log.i(TAG, "onCreate1");
|
||||
config.setModelPath("models/ch_PP-OCRv2"); // 不使用 "/" 开头的路径表示安装包中 assets 目录下的文件,例如当前表示 assets/models/ocr_v2_for_cpu
|
||||
//config.modelPath = "/sdcard/Android/data/com.equationl.paddleocr4android.app/files/models" // 使用 "/" 表示手机储存路径,测试时请将下载的三个模型放置于该目录下
|
||||
|
||||
/*
|
||||
config.setClsModelFilename("cls.nb"); // cls 模型文件名
|
||||
config.setDetModelFilename("det_db.nb"); // det 模型文件名
|
||||
config.setRecModelFilename("rec_crnn.nb"); // rec 模型文件名
|
||||
*/
|
||||
|
||||
/* already true by default
|
||||
config.setIsRunDet(true);
|
||||
config.setIsRunCls(true);
|
||||
config.setIsRunRec(true);*/
|
||||
|
||||
|
||||
// 运行全部模型
|
||||
config.setRunType(RunType.All);
|
||||
|
||||
// 使用所有核心运行
|
||||
config.setCpuPowerMode(LitePowerMode.LITE_POWER_FULL);
|
||||
|
||||
// 绘制文本位置
|
||||
//config.setIsDrwwTextPositionBox(true);
|
||||
|
||||
// 如果是原始模型,则使用 FP16 精度
|
||||
config.setRecRunPrecision(RunPrecision.LiteFp16);
|
||||
config.setDetRunPrecision(RunPrecision.LiteFp16);
|
||||
config.setClsRunPrecision(RunPrecision.LiteFp16);
|
||||
|
||||
Log.i(TAG, "onCreate2");
|
||||
|
||||
// 如果是量化模型则使用 int8 精度
|
||||
//config.recRunPrecision(RunPrecision.LiteInt8
|
||||
//config.detRunPrecision(RunPrecision.LiteInt8
|
||||
//config.clsRunPrecision(RunPrecision.LiteInt8
|
||||
|
||||
// 1.同步初始化
|
||||
/*ocr.initModelSync(config).fold(
|
||||
{
|
||||
if (it) {
|
||||
Log.i(TAG, "onCreate: init success")
|
||||
}
|
||||
},
|
||||
{
|
||||
it.printStackTrace()
|
||||
}
|
||||
)*/
|
||||
|
||||
// 2.异步初始化
|
||||
ocr = new OCR(this);
|
||||
ocr.initModel(config, new OcrInitCallback() {
|
||||
@Override
|
||||
public void onSuccess() {
|
||||
Log.i(TAG, "onSuccess: 初始化成功");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFail(Throwable e) {
|
||||
Log.e(TAG, "onFail: 初始化失败", e);
|
||||
}
|
||||
});
|
||||
|
||||
Log.i(TAG, "onCreate3");
|
||||
|
||||
// create store dir
|
||||
File externalFilesDir = getExternalFilesDir(null);
|
||||
if (externalFilesDir != null) {
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
package org.cagnulen.qdomyoszwift;
|
||||
|
||||
import android.app.ActivityManager;
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.provider.Settings;
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
import android.view.View;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
import android.widget.Toast;
|
||||
import android.os.Looper;
|
||||
import android.os.Handler;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
public class WearableController {
|
||||
static Context _context;
|
||||
static Intent _intent = null;
|
||||
|
||||
public static void start(Context context) {
|
||||
_context = context;
|
||||
|
||||
if(_intent == null)
|
||||
_intent = new Intent(context, WearableMessageListenerService.class);
|
||||
// FloatingWindowGFG service is started
|
||||
context.startService(_intent);
|
||||
Log.v("WearableController", "started");
|
||||
}
|
||||
|
||||
public static int getHeart() {
|
||||
return WearableMessageListenerService.getHeart();
|
||||
}
|
||||
}
|
||||
@@ -1,131 +0,0 @@
|
||||
package org.cagnulen.qdomyoszwift;
|
||||
|
||||
import android.app.Service;
|
||||
import android.content.Intent;
|
||||
import android.os.IBinder;
|
||||
import com.google.android.gms.common.api.GoogleApiClient;
|
||||
import com.google.android.gms.common.api.PendingResult;
|
||||
import com.google.android.gms.common.api.ResultCallback;
|
||||
import com.google.android.gms.wearable.MessageClient;
|
||||
import com.google.android.gms.wearable.DataClient;
|
||||
import com.google.android.gms.wearable.DataEvent;
|
||||
import com.google.android.gms.wearable.DataEventBuffer;
|
||||
import com.google.android.gms.wearable.MessageEvent;
|
||||
import com.google.android.gms.wearable.Wearable;
|
||||
import com.google.android.gms.common.ConnectionResult;
|
||||
import com.google.android.gms.wearable.DataItemBuffer;
|
||||
import com.google.android.gms.wearable.DataMap;
|
||||
import android.util.Log;
|
||||
import android.os.Bundle;
|
||||
import com.google.android.gms.common.api.Status;
|
||||
import java.io.InputStream;
|
||||
|
||||
public class WearableMessageListenerService extends Service implements
|
||||
MessageClient.OnMessageReceivedListener, GoogleApiClient.ConnectionCallbacks,GoogleApiClient.OnConnectionFailedListener,DataClient.OnDataChangedListener {
|
||||
|
||||
private GoogleApiClient googleApiClient;
|
||||
private MessageClient mWearableClient;
|
||||
private String TAG = "WearableMessageListenerService";
|
||||
private static int heart_rate = 0;
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
Log.v("WearableMessageListenerService","onCreate");
|
||||
}
|
||||
|
||||
public static int getHeart() {
|
||||
return heart_rate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
// Your service logic here
|
||||
|
||||
googleApiClient = new GoogleApiClient.Builder(this)
|
||||
.addApi(Wearable.API)
|
||||
.addConnectionCallbacks (this)
|
||||
.addOnConnectionFailedListener(this)
|
||||
.build();
|
||||
|
||||
googleApiClient.connect();
|
||||
|
||||
// Register the MessageClient.OnMessageReceivedListener
|
||||
mWearableClient = Wearable.getMessageClient(this);
|
||||
mWearableClient.addListener(this);
|
||||
Wearable.getDataClient(this).addListener(this);
|
||||
|
||||
Log.v("WearableMessageListenerService","onStartCommand");
|
||||
|
||||
// Return START_STICKY to restart the service if it's killed by the system
|
||||
return START_STICKY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDataChanged(DataEventBuffer dataEvents) {
|
||||
for (DataEvent event : dataEvents) {
|
||||
if (event.getType() == DataEvent.TYPE_DELETED) {
|
||||
Log.d(TAG, "DataItem deleted: " + event.getDataItem().getUri());
|
||||
} else if (event.getType() == DataEvent.TYPE_CHANGED) {
|
||||
Log.d(TAG, "DataItem changed: " + event.getDataItem().getUri() + " " + event.getDataItem().getUri().getPath());
|
||||
if(event.getDataItem().getUri().getPath().equals("/qz")) {
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
DataItemBuffer result = Wearable.DataApi.getDataItems(googleApiClient).await();
|
||||
if (result.getStatus().isSuccess()) {
|
||||
if (result.getCount() == 1) {
|
||||
heart_rate = DataMap.fromByteArray(result.get(0).getData())
|
||||
.getInt("heart_rate", 0);
|
||||
} else {
|
||||
Log.e(TAG, "Unexpected number of DataItems found.\n"
|
||||
+ "\tExpected: 1\n"
|
||||
+ "\tActual: " + result.getCount());
|
||||
}
|
||||
} else if (Log.isLoggable(TAG, Log.DEBUG)) {
|
||||
Log.d(TAG, "onHandleIntent: failed to get current alarm state");
|
||||
}
|
||||
Log.d(TAG, "Heart: " + heart_rate);
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onConnected(Bundle bundle) {
|
||||
Log.v("WearableMessageListenerService","onConnected");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConnectionSuspended(int i) {
|
||||
Log.v("WearableMessageListenerService","onConnectionSuspended");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConnectionFailed(ConnectionResult connectionResult) {
|
||||
Log.v("WearableMessageListenerService","onConnectionFailed");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMessageReceived(final MessageEvent messageEvent) {
|
||||
String path = messageEvent.getPath();
|
||||
byte[] data = messageEvent.getData();
|
||||
|
||||
// Handle the received message data here
|
||||
String messageData = new String(data); // Assuming it's a simple string message
|
||||
|
||||
Log.v("Wearable", path);
|
||||
Log.v("Wearable", messageData);
|
||||
|
||||
// You can then perform actions or update data in your service based on the received message
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
// This service does not support binding
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@ package com.cgutman.androidremotedebugger.console;
|
||||
import android.widget.TextView;
|
||||
|
||||
public class ConsoleBuffer {
|
||||
public char[] buffer;
|
||||
private char[] buffer;
|
||||
private int amountPopulated;
|
||||
|
||||
public ConsoleBuffer(int bufferSize)
|
||||
|
||||
@@ -129,7 +129,6 @@ void apexbike::serviceDiscovered(const QBluetoothUuid &gatt) {
|
||||
}
|
||||
|
||||
void apexbike::characteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &newValue) {
|
||||
QDateTime now = QDateTime::currentDateTime();
|
||||
// qDebug() << "characteristicChanged" << characteristic.uuid() << newValue << newValue.length();
|
||||
Q_UNUSED(characteristic);
|
||||
QSettings settings;
|
||||
@@ -160,7 +159,7 @@ void apexbike::characteristicChanged(const QLowEnergyCharacteristic &characteris
|
||||
} else {
|
||||
Speed = metric::calculateSpeedFromPower(
|
||||
watts(), Inclination.value(), Speed.value(),
|
||||
fabs(now.msecsTo(Speed.lastChanged()) / 1000.0), this->speedLimit());
|
||||
fabs(QDateTime::currentDateTime().msecsTo(Speed.lastChanged()) / 1000.0), this->speedLimit());
|
||||
}
|
||||
if (watts())
|
||||
KCal +=
|
||||
@@ -168,17 +167,17 @@ void apexbike::characteristicChanged(const QLowEnergyCharacteristic &characteris
|
||||
settings.value(QZSettings::weight, QZSettings::default_weight).toFloat() * 3.5) /
|
||||
200.0) /
|
||||
(60000.0 / ((double)lastRefreshCharacteristicChanged.msecsTo(
|
||||
now)))); //(( (0.048* Output in watts +1.19) * body weight in kg
|
||||
QDateTime::currentDateTime())))); //(( (0.048* Output in watts +1.19) * body weight in kg
|
||||
//* 3.5) / 200 ) / 60
|
||||
Distance += ((Speed.value() / 3600000.0) *
|
||||
((double)lastRefreshCharacteristicChanged.msecsTo(now)));
|
||||
((double)lastRefreshCharacteristicChanged.msecsTo(QDateTime::currentDateTime())));
|
||||
|
||||
if (Cadence.value() > 0) {
|
||||
CrankRevs++;
|
||||
LastCrankEventTime += (uint16_t)(1024.0 / (((double)(Cadence.value())) / 60.0));
|
||||
}
|
||||
|
||||
lastRefreshCharacteristicChanged = now;
|
||||
lastRefreshCharacteristicChanged = QDateTime::currentDateTime();
|
||||
|
||||
#ifdef Q_OS_ANDROID
|
||||
if (settings.value(QZSettings::ant_heart, QZSettings::default_ant_heart).toBool()) {
|
||||
|
||||
@@ -142,7 +142,6 @@ void bhfitnesselliptical::characteristicChanged(const QLowEnergyCharacteristic &
|
||||
settings.value(QZSettings::heart_ignore_builtin, QZSettings::default_heart_ignore_builtin).toBool();
|
||||
|
||||
emit debug(QStringLiteral(" << ") + newValue.toHex(' '));
|
||||
QDateTime now = QDateTime::currentDateTime();
|
||||
|
||||
if (characteristic.uuid() == QBluetoothUuid::HeartRate && newValue.length() > 1) {
|
||||
Heart = (uint8_t)newValue[1];
|
||||
@@ -192,7 +191,7 @@ void bhfitnesselliptical::characteristicChanged(const QLowEnergyCharacteristic &
|
||||
} else {
|
||||
Speed = metric::calculateSpeedFromPower(
|
||||
watts(), Inclination.value(), Speed.value(),
|
||||
fabs(now.msecsTo(Speed.lastChanged()) / 1000.0),
|
||||
fabs(QDateTime::currentDateTime().msecsTo(Speed.lastChanged()) / 1000.0),
|
||||
0 /* not useful for elliptical*/);
|
||||
}
|
||||
index += 2;
|
||||
@@ -242,7 +241,7 @@ void bhfitnesselliptical::characteristicChanged(const QLowEnergyCharacteristic &
|
||||
index += 3;
|
||||
} else {
|
||||
Distance += ((Speed.value() / 3600000.0) *
|
||||
((double)lastRefreshCharacteristicChanged.msecsTo(now)));
|
||||
((double)lastRefreshCharacteristicChanged.msecsTo(QDateTime::currentDateTime())));
|
||||
}
|
||||
|
||||
emit debug(QStringLiteral("Current Distance: ") + QString::number(Distance.value()));
|
||||
@@ -289,7 +288,7 @@ void bhfitnesselliptical::characteristicChanged(const QLowEnergyCharacteristic &
|
||||
settings.value(QZSettings::weight, QZSettings::default_weight).toFloat() * 3.5) /
|
||||
200.0) /
|
||||
(60000.0 / ((double)lastRefreshCharacteristicChanged.msecsTo(
|
||||
now)))); //(( (0.048* Output in watts +1.19) * body weight in
|
||||
QDateTime::currentDateTime())))); //(( (0.048* Output in watts +1.19) * body weight in
|
||||
// kg * 3.5) / 200 ) / 60
|
||||
}
|
||||
|
||||
@@ -302,7 +301,7 @@ void bhfitnesselliptical::characteristicChanged(const QLowEnergyCharacteristic &
|
||||
#endif
|
||||
{
|
||||
if (Flags.heartRate && !disable_hr_frommachinery && newValue.length() > index) {
|
||||
Heart = ((double)(((uint8_t)newValue.at(index))));
|
||||
Heart = ((double)((newValue.at(index))));
|
||||
// index += 1; // NOTE: clang-analyzer-deadcode.DeadStores
|
||||
emit debug(QStringLiteral("Current Heart: ") + QString::number(Heart.value()));
|
||||
} else {
|
||||
@@ -327,7 +326,7 @@ void bhfitnesselliptical::characteristicChanged(const QLowEnergyCharacteristic &
|
||||
LastCrankEventTime += (uint16_t)(1024.0 / (((double)(Cadence.value())) / 60.0));
|
||||
}
|
||||
|
||||
lastRefreshCharacteristicChanged = now;
|
||||
lastRefreshCharacteristicChanged = QDateTime::currentDateTime();
|
||||
|
||||
if (heartRateBeltName.startsWith(QStringLiteral("Disabled")) &&
|
||||
(!Flags.heartRate || Heart.value() == 0 || disable_hr_frommachinery)) {
|
||||
|
||||
@@ -116,7 +116,6 @@ void bike::clearStats() {
|
||||
Speed.clear(false);
|
||||
KCal.clear(true);
|
||||
Distance.clear(true);
|
||||
Distance1s.clear(true);
|
||||
Heart.clear(false);
|
||||
m_jouls.clear(true);
|
||||
elevationAcc = 0;
|
||||
@@ -141,7 +140,6 @@ void bike::setPaused(bool p) {
|
||||
Speed.setPaused(p);
|
||||
KCal.setPaused(p);
|
||||
Distance.setPaused(p);
|
||||
Distance1s.setPaused(p);
|
||||
Heart.setPaused(p);
|
||||
m_jouls.setPaused(p);
|
||||
m_watt.setPaused(p);
|
||||
@@ -163,7 +161,6 @@ void bike::setLap() {
|
||||
Speed.setLap(false);
|
||||
KCal.setLap(true);
|
||||
Distance.setLap(true);
|
||||
Distance1s.setLap(true);
|
||||
Heart.setLap(false);
|
||||
m_jouls.setLap(true);
|
||||
m_watt.setLap(false);
|
||||
@@ -291,8 +288,6 @@ uint16_t bike::wattFromHR(bool useSpeedAndCadence) {
|
||||
} else {
|
||||
watt = 0;
|
||||
}
|
||||
} else {
|
||||
watt = currentCadence().value() * 1.2; // random value cloned from Zwift when HR is not available
|
||||
}
|
||||
return watt;
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ class bike : public bluetoothdevice {
|
||||
public:
|
||||
bike();
|
||||
|
||||
virtualbike *VirtualBike();
|
||||
virtualbike * VirtualBike();
|
||||
|
||||
metric lastRequestedResistance();
|
||||
metric lastRequestedPelotonResistance();
|
||||
@@ -36,8 +36,8 @@ class bike : public bluetoothdevice {
|
||||
uint8_t metrics_override_heartrate() override;
|
||||
void setGears(double d);
|
||||
double gears();
|
||||
void setSpeedLimit(double speed) { m_speedLimit = speed; }
|
||||
double speedLimit() { return m_speedLimit; }
|
||||
void setSpeedLimit(double speed) {m_speedLimit = speed;}
|
||||
double speedLimit() {return m_speedLimit;}
|
||||
|
||||
/**
|
||||
* @brief currentSteeringAngle Gets a metric object to get or set the current steering angle
|
||||
@@ -46,7 +46,6 @@ class bike : public bluetoothdevice {
|
||||
*/
|
||||
metric currentSteeringAngle() { return m_steeringAngle; }
|
||||
virtual bool inclinationAvailableByHardware();
|
||||
bool ergModeSupportedAvailableByHardware() { return ergModeSupported; }
|
||||
|
||||
public Q_SLOTS:
|
||||
void changeResistance(resistance_t res) override;
|
||||
|
||||
@@ -192,7 +192,6 @@ void bkoolbike::serviceDiscovered(const QBluetoothUuid &gatt) {
|
||||
}
|
||||
|
||||
void bkoolbike::characteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &newValue) {
|
||||
QDateTime now = QDateTime::currentDateTime();
|
||||
// qDebug() << "characteristicChanged" << characteristic.uuid() << newValue << newValue.length();
|
||||
Q_UNUSED(characteristic);
|
||||
QSettings settings;
|
||||
@@ -254,8 +253,8 @@ void bkoolbike::characteristicChanged(const QLowEnergyCharacteristic &characteri
|
||||
if (cadence >= 0 && cadence < 255) {
|
||||
Cadence = cadence;
|
||||
}
|
||||
lastGoodCadence = now;
|
||||
} else if (lastGoodCadence.msecsTo(now) > 2000) {
|
||||
lastGoodCadence = QDateTime::currentDateTime();
|
||||
} else if (lastGoodCadence.msecsTo(QDateTime::currentDateTime()) > 2000) {
|
||||
Cadence = 0;
|
||||
}
|
||||
|
||||
@@ -267,7 +266,7 @@ void bkoolbike::characteristicChanged(const QLowEnergyCharacteristic &characteri
|
||||
.toDouble();
|
||||
|
||||
Distance += ((Speed.value() / 3600000.0) *
|
||||
((double)lastRefreshCharacteristicChanged.msecsTo(now)));
|
||||
((double)lastRefreshCharacteristicChanged.msecsTo(QDateTime::currentDateTime())));
|
||||
|
||||
// Resistance = ((double)(((uint16_t)((uint8_t)newValue.at(index + 1)) << 8) |
|
||||
// (uint16_t)((uint8_t)newValue.at(index)))); debug("Current Resistance: " +
|
||||
@@ -302,9 +301,9 @@ void bkoolbike::characteristicChanged(const QLowEnergyCharacteristic &characteri
|
||||
settings.value(QZSettings::weight, QZSettings::default_weight).toFloat() * 3.5) /
|
||||
200.0) /
|
||||
(60000.0 / ((double)lastRefreshCharacteristicChanged.msecsTo(
|
||||
now)))); //(( (0.048* Output in watts +1.19) * body weight in
|
||||
QDateTime::currentDateTime())))); //(( (0.048* Output in watts +1.19) * body weight in
|
||||
// kg * 3.5) / 200 ) / 60
|
||||
lastRefreshCharacteristicChanged = now;
|
||||
lastRefreshCharacteristicChanged = QDateTime::currentDateTime();
|
||||
|
||||
emit debug(QStringLiteral("Current CrankRevsRead: ") + QString::number(CrankRevsRead));
|
||||
emit debug(QStringLiteral("Last CrankEventTime: ") + QString::number(LastCrankEventTime));
|
||||
@@ -385,8 +384,8 @@ void bkoolbike::characteristicChanged(const QLowEnergyCharacteristic &characteri
|
||||
if (cadence >= 0) {
|
||||
Cadence = cadence;
|
||||
}
|
||||
lastGoodCadence = now;
|
||||
} else if (lastGoodCadence.msecsTo(now) > 2000) {
|
||||
lastGoodCadence = QDateTime::currentDateTime();
|
||||
} else if (lastGoodCadence.msecsTo(QDateTime::currentDateTime()) > 2000) {
|
||||
Cadence = 0;
|
||||
}
|
||||
}
|
||||
@@ -404,12 +403,12 @@ void bkoolbike::characteristicChanged(const QLowEnergyCharacteristic &characteri
|
||||
} else {
|
||||
Speed = metric::calculateSpeedFromPower(
|
||||
watts(), Inclination.value(), Speed.value(),
|
||||
fabs(now.msecsTo(Speed.lastChanged()) / 1000.0), this->speedLimit());
|
||||
fabs(QDateTime::currentDateTime().msecsTo(Speed.lastChanged()) / 1000.0), this->speedLimit());
|
||||
}
|
||||
emit debug(QStringLiteral("Current Speed: ") + QString::number(Speed.value()));
|
||||
|
||||
Distance += ((Speed.value() / 3600000.0) *
|
||||
((double)lastRefreshCharacteristicChanged.msecsTo(now)));
|
||||
((double)lastRefreshCharacteristicChanged.msecsTo(QDateTime::currentDateTime())));
|
||||
emit debug(QStringLiteral("Current Distance: ") + QString::number(Distance.value()));
|
||||
|
||||
// if we change this, also change the wattsFromResistance function. We can create a standard function in
|
||||
@@ -457,7 +456,7 @@ void bkoolbike::characteristicChanged(const QLowEnergyCharacteristic &characteri
|
||||
settings.value(QZSettings::weight, QZSettings::default_weight).toFloat() * 3.5) /
|
||||
200.0) /
|
||||
(60000.0 / ((double)lastRefreshCharacteristicChanged.msecsTo(
|
||||
now)))); //(( (0.048* Output in watts +1.19) * body weight
|
||||
QDateTime::currentDateTime())))); //(( (0.048* Output in watts +1.19) * body weight
|
||||
// in kg * 3.5) / 200 ) / 60
|
||||
emit debug(QStringLiteral("Current KCal: ") + QString::number(KCal.value()));
|
||||
}
|
||||
|
||||
@@ -49,6 +49,25 @@ bluetooth::bluetooth(bool logs, const QString &deviceName, bool noWriteResistanc
|
||||
this->signalBluetoothDeviceConnected(pelotonBike);
|
||||
}
|
||||
|
||||
// TO REMOVE
|
||||
bool fakedevice_treadmill =
|
||||
settings.value(QZSettings::fakedevice_treadmill, QZSettings::default_fakedevice_treadmill).toBool();
|
||||
if(fakedevice_treadmill) {
|
||||
fakeTreadmill = new faketreadmill(noWriteResistance, noHeartService, false);
|
||||
emit deviceConnected(QBluetoothDeviceInfo());
|
||||
connect(fakeTreadmill, &bluetoothdevice::connectedAndDiscovered, this,
|
||||
&bluetooth::connectedAndDiscovered);
|
||||
connect(fakeTreadmill, &faketreadmill::inclinationChanged, this, &bluetooth::inclinationChanged);
|
||||
// connect(cscBike, SIGNAL(disconnected()), this, SLOT(restart()));
|
||||
// connect(this, SIGNAL(searchingStop()), fakeBike, SLOT(searchingStop())); //NOTE: Commented due to
|
||||
// #358
|
||||
if (this->discoveryAgent && !this->discoveryAgent->isActive()) {
|
||||
emit searchingStop();
|
||||
}
|
||||
this->signalBluetoothDeviceConnected(fakeTreadmill);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
schwinnIC4Bike = (schwinnic4bike *)new bike();
|
||||
// this signal is not associated to anything in this moment, since the homeform is not loaded yet
|
||||
@@ -109,9 +128,8 @@ void bluetooth::finished() {
|
||||
QSettings settings;
|
||||
QString nordictrack_2950_ip =
|
||||
settings.value(QZSettings::nordictrack_2950_ip, QZSettings::default_nordictrack_2950_ip).toString();
|
||||
QString tdf_10_ip = settings.value(QZSettings::tdf_10_ip, QZSettings::default_tdf_10_ip).toString();
|
||||
// wifi devices on windows
|
||||
if (!nordictrack_2950_ip.isEmpty() || !tdf_10_ip.isEmpty()) {
|
||||
if (!nordictrack_2950_ip.isEmpty()) {
|
||||
// faking a bluetooth device
|
||||
qDebug() << "faking a bluetooth device for nordictrack_2950_ip";
|
||||
deviceDiscovered(QBluetoothDeviceInfo());
|
||||
@@ -399,7 +417,6 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) {
|
||||
settings.value(QZSettings::fakedevice_treadmill, QZSettings::default_fakedevice_treadmill).toBool();
|
||||
bool pafers_treadmill = settings.value(QZSettings::pafers_treadmill, QZSettings::default_pafers_treadmill).toBool();
|
||||
QString proformtdf4ip = settings.value(QZSettings::proformtdf4ip, QZSettings::default_proformtdf4ip).toString();
|
||||
QString proformtdf1ip = settings.value(QZSettings::proformtdf1ip, QZSettings::default_proformtdf1ip).toString();
|
||||
QString proformtreadmillip =
|
||||
settings.value(QZSettings::proformtreadmillip, QZSettings::default_proformtreadmillip).toString();
|
||||
QString nordictrack_2950_ip =
|
||||
@@ -424,10 +441,6 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) {
|
||||
bool sole_inclination =
|
||||
settings.value(QZSettings::sole_treadmill_inclination, QZSettings::default_sole_treadmill_inclination).toBool();
|
||||
QString ftms_rower = settings.value(QZSettings::ftms_rower, QZSettings::default_ftms_rower).toString();
|
||||
QString ftms_bike = settings.value(QZSettings::ftms_bike, QZSettings::default_ftms_bike).toString();
|
||||
QString ftms_treadmill = settings.value(QZSettings::ftms_treadmill, QZSettings::default_ftms_treadmill).toString();
|
||||
bool saris_trainer = settings.value(QZSettings::saris_trainer, QZSettings::default_saris_trainer).toBool();
|
||||
bool iconsole_elliptical = settings.value(QZSettings::iconsole_elliptical, QZSettings::default_iconsole_elliptical).toBool();
|
||||
|
||||
if (!heartRateBeltFound) {
|
||||
|
||||
@@ -657,21 +670,6 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) {
|
||||
emit searchingStop();
|
||||
}
|
||||
this->signalBluetoothDeviceConnected(proformWifiBike);
|
||||
} else if (!proformtdf1ip.isEmpty() && !proformTelnetBike) {
|
||||
this->stopDiscovery();
|
||||
proformTelnetBike =
|
||||
new proformtelnetbike(noWriteResistance, noHeartService, bikeResistanceOffset, bikeResistanceGain);
|
||||
emit deviceConnected(b);
|
||||
connect(proformTelnetBike, &bluetoothdevice::connectedAndDiscovered, this,
|
||||
&bluetooth::connectedAndDiscovered);
|
||||
// connect(cscBike, SIGNAL(disconnected()), this, SLOT(restart()));
|
||||
connect(proformTelnetBike, &proformtelnetbike::debug, this, &bluetooth::debug);
|
||||
proformTelnetBike->deviceDiscovered(b);
|
||||
// connect(this, SIGNAL(searchingStop()), cscBike, SLOT(searchingStop())); //NOTE: Commented due to #358
|
||||
if (this->discoveryAgent && !this->discoveryAgent->isActive()) {
|
||||
emit searchingStop();
|
||||
}
|
||||
this->signalBluetoothDeviceConnected(proformTelnetBike);
|
||||
#ifndef Q_OS_IOS
|
||||
} else if (!computrainerSerialPort.isEmpty() && !computrainerBike) {
|
||||
this->stopDiscovery();
|
||||
@@ -732,8 +730,7 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) {
|
||||
this->signalBluetoothDeviceConnected(nordictrackifitadbTreadmill);
|
||||
} else if (!tdf_10_ip.isEmpty() && !nordictrackifitadbBike) {
|
||||
this->stopDiscovery();
|
||||
nordictrackifitadbBike = new nordictrackifitadbbike(noWriteResistance, noHeartService,
|
||||
bikeResistanceOffset, bikeResistanceGain);
|
||||
nordictrackifitadbBike = new nordictrackifitadbbike(noWriteResistance, noHeartService);
|
||||
emit deviceConnected(b);
|
||||
connect(nordictrackifitadbBike, &bluetoothdevice::connectedAndDiscovered, this,
|
||||
&bluetooth::connectedAndDiscovered);
|
||||
@@ -841,8 +838,7 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) {
|
||||
emit searchingStop();
|
||||
}
|
||||
this->signalBluetoothDeviceConnected(domyosElliptical);
|
||||
} else if ((b.name().toUpper().startsWith(QStringLiteral("YPOO-U3-")) ||
|
||||
(b.name().startsWith(QStringLiteral("FS-")) && iconsole_elliptical)) && !ypooElliptical && filter) {
|
||||
} else if (b.name().toUpper().startsWith(QStringLiteral("YPOO-U3-")) && !ypooElliptical && filter) {
|
||||
this->setLastBluetoothDevice(b);
|
||||
this->stopDiscovery();
|
||||
ypooElliptical =
|
||||
@@ -858,8 +854,7 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) {
|
||||
emit searchingStop();
|
||||
}
|
||||
this->signalBluetoothDeviceConnected(ypooElliptical);
|
||||
} else if ((b.name().toUpper().startsWith(QStringLiteral("NAUTILUS E")) ||
|
||||
b.name().toUpper().startsWith(QStringLiteral("NAUTILUS M"))) &&
|
||||
} else if ((b.name().toUpper().startsWith(QStringLiteral("NAUTILUS E"))) &&
|
||||
!nautilusElliptical && // NAUTILUS E616
|
||||
filter) {
|
||||
this->setLastBluetoothDevice(b);
|
||||
@@ -1022,9 +1017,7 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) {
|
||||
b.name().toUpper().startsWith(QStringLiteral("KS-HDSC-X21C")) ||
|
||||
b.name().toUpper().startsWith(QStringLiteral("KS-HDSY-X21C")) ||
|
||||
b.name().toUpper().startsWith(QStringLiteral("KS-NACH-X21C")) ||
|
||||
b.name().toUpper().startsWith(QStringLiteral("KS-NGCH-X21C")) ||
|
||||
// KingSmith Walking Pad G1
|
||||
b.name().toUpper().startsWith(QStringLiteral("KS-NGCH-G1C"))) &&
|
||||
b.name().toUpper().startsWith(QStringLiteral("KS-NGCH-X21C"))) &&
|
||||
!kingsmithR2Treadmill && filter) {
|
||||
this->setLastBluetoothDevice(b);
|
||||
this->stopDiscovery();
|
||||
@@ -1051,7 +1044,6 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) {
|
||||
b.name().toUpper().startsWith(QStringLiteral("WALKINGPAD")) ||
|
||||
!b.name().toUpper().compare(QStringLiteral("RE")) || // just "RE"
|
||||
b.name().toUpper().startsWith(QStringLiteral("KS-H")) ||
|
||||
b.name().toUpper().startsWith(QStringLiteral("KS-BLC")) || // Walkingpad C2 #1672
|
||||
b.name().toUpper().startsWith(
|
||||
QStringLiteral("KS-BLR"))) && // Treadmill KingSmith WalkingPad R2 Pro KS-HCR1AA
|
||||
!kingsmithR1ProTreadmill &&
|
||||
@@ -1116,7 +1108,7 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) {
|
||||
if (this->discoveryAgent && !this->discoveryAgent->isActive())
|
||||
emit searchingStop();
|
||||
this->signalBluetoothDeviceConnected(trueTreadmill);
|
||||
} else if (((b.name().toUpper().startsWith(QStringLiteral("F80")) && sole_inclination) ||
|
||||
} else if ((b.name().toUpper().startsWith(QStringLiteral("F80")) ||
|
||||
b.name().toUpper().startsWith(QStringLiteral("F65")) ||
|
||||
b.name().toUpper().startsWith(QStringLiteral("TT8")) ||
|
||||
b.name().toUpper().startsWith(QStringLiteral("F63")) ||
|
||||
@@ -1187,20 +1179,16 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) {
|
||||
b.name().toUpper().startsWith(QStringLiteral("CT800")) || // FTMS
|
||||
b.name().toUpper().startsWith(QStringLiteral("TRX4500")) || // FTMS
|
||||
b.name().toUpper().startsWith(QStringLiteral("MATRIXTF50")) || // FTMS
|
||||
b.name().toUpper().startsWith(QStringLiteral("T01_")) || // FTMS
|
||||
(b.name().toUpper().startsWith(QStringLiteral("TF-")) &&
|
||||
horizon_treadmill_force_ftms) || // FTMS, TF-769DF2
|
||||
((b.name().toUpper().startsWith(QStringLiteral("TOORX")) ||
|
||||
(b.name().toUpper().startsWith(QStringLiteral("I-CONSOLE+")))) &&
|
||||
!toorx_ftms && toorx_ftms_treadmill) ||
|
||||
!b.name().compare(ftms_treadmill, Qt::CaseInsensitive) ||
|
||||
b.name().toUpper().startsWith(QStringLiteral("MOBVOI TM")) || // FTMS
|
||||
b.name().toUpper().startsWith(QStringLiteral("KETTLER TREADMILL")) || // FTMS
|
||||
b.name().toUpper().startsWith(QStringLiteral("ASSAULTRUNNER")) || // FTMS
|
||||
(b.name().toUpper().startsWith(QStringLiteral("CTM")) && b.name().length() >= 15) || // FTMS
|
||||
(b.name().toUpper().startsWith(QStringLiteral("F85")) && !sole_inclination) || // FMTS
|
||||
(b.name().toUpper().startsWith(QStringLiteral("F80")) && !sole_inclination) || // FMTS
|
||||
(b.name().toUpper().startsWith(QStringLiteral("ANPLUS-"))) || // FTMS
|
||||
b.name().toUpper().startsWith(QStringLiteral("ESANGLINKER"))) &&
|
||||
!horizonTreadmill && filter) {
|
||||
this->setLastBluetoothDevice(b);
|
||||
@@ -1229,11 +1217,7 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) {
|
||||
} else if ((b.name().toUpper().startsWith(QStringLiteral("MYRUN ")) ||
|
||||
b.name().toUpper().startsWith(QStringLiteral("MERACH-U3")) // FTMS
|
||||
) &&
|
||||
!technogymmyrunTreadmill
|
||||
#ifndef Q_OS_IOS
|
||||
&& !technogymmyrunrfcommTreadmill
|
||||
#endif
|
||||
&& filter) {
|
||||
!technogymmyrunTreadmill && filter) {
|
||||
this->setLastBluetoothDevice(b);
|
||||
this->stopDiscovery();
|
||||
bool technogym_myrun_treadmill_experimental =
|
||||
@@ -1293,9 +1277,9 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) {
|
||||
this->signalBluetoothDeviceConnected(technogymmyrunrfcommTreadmill);
|
||||
}
|
||||
#endif
|
||||
} else if ((b.name().toUpper().startsWith("TACX ") ||
|
||||
} else if ((b.name().toUpper().startsWith("TACX NEO") ||
|
||||
b.name().toUpper().startsWith(QStringLiteral("TACX FLOW")) ||
|
||||
b.name().toUpper().startsWith(QStringLiteral("THINK X")) ||
|
||||
b.address() == QBluetoothAddress("C1:14:D9:9C:FB:01") || // specific TACX NEO 2 #1707
|
||||
(b.name().toUpper().startsWith("TACX SMART BIKE"))) &&
|
||||
!tacxneo2Bike && filter) {
|
||||
this->setLastBluetoothDevice(b);
|
||||
@@ -1331,33 +1315,28 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) {
|
||||
npeCableBike->deviceDiscovered(b);
|
||||
this->signalBluetoothDeviceConnected(npeCableBike);
|
||||
} else if (((b.name().startsWith("FS-") && hammerRacerS) ||
|
||||
(b.name().toUpper().startsWith("DI") && b.name().length() == 2) || // Elite smart trainer #1682
|
||||
(b.name().toUpper().startsWith("DHZ-")) || // JK fitness 577
|
||||
(b.name().toUpper().startsWith("MKSM")) || // MKSM3600036
|
||||
(b.name().toUpper().startsWith("YS_C1_")) || // Yesoul C1H
|
||||
(b.name().toUpper().startsWith("YS_G1_")) || // Yesoul S3
|
||||
(b.name().toUpper().startsWith("DS25-")) || // Bodytone DS25
|
||||
(b.name().toUpper().startsWith("DHZ-")) || // JK fitness 577
|
||||
(b.name().toUpper().startsWith("MKSM")) || // MKSM3600036
|
||||
(b.name().toUpper().startsWith("YS_C1_")) || // Yesoul C1H
|
||||
(b.name().toUpper().startsWith("YS_G1_")) || // Yesoul S3
|
||||
(b.name().toUpper().startsWith("DS25-")) || // Bodytone DS25
|
||||
(b.name().toUpper().startsWith("SCHWINN 510T")) ||
|
||||
(b.name().toUpper().startsWith("ZWIFT HUB")) || (b.name().toUpper().startsWith("MAGNUS ")) ||
|
||||
(b.name().toUpper().startsWith("HAMMER ") && !power_as_bike && !saris_trainer) || // HAMMER 64123
|
||||
(b.name().toUpper().startsWith("HAMMER ")) || // HAMMER 64123
|
||||
(b.name().toUpper().startsWith("FLXCY-")) || // Pro FlexBike
|
||||
(b.name().toUpper().startsWith("QB-WC01")) || // Nexgim QB-C01 smart bike
|
||||
(b.name().toUpper().startsWith("XBR55")) || // Sprint XBR555
|
||||
(b.name().toUpper().startsWith("ECHO_BIKE_")) || // Rogue echo bike V3.0
|
||||
(b.name().toUpper().startsWith("EW-JS-")) || // EW-JS-4990
|
||||
(b.name().toUpper().startsWith("DT-") && b.name().length() >= 14) || // SOLE SB700
|
||||
(b.name().toUpper().startsWith("URSB") && b.name().length() == 7) || // URSB005
|
||||
(b.name().toUpper().startsWith("DBF") && b.name().length() == 6) || // DBF135
|
||||
(b.name().toUpper().startsWith(ftmsAccessoryName.toUpper()) &&
|
||||
settings.value(QZSettings::ss2k_peloton, QZSettings::default_ss2k_peloton)
|
||||
.toBool()) || // ss2k on a peloton bike
|
||||
(b.name().toUpper().startsWith("KICKR CORE")) ||
|
||||
(b.name().toUpper().startsWith("ZUMO")) || (b.name().toUpper().startsWith("XS08-")) ||
|
||||
(b.name().toUpper().startsWith("B94")) || (b.name().toUpper().startsWith("STAGES BIKE")) ||
|
||||
(b.name().toUpper().startsWith("SUITO")) || (b.name().toUpper().startsWith("D2RIDE")) ||
|
||||
(b.name().toUpper().startsWith("DIRETO XR")) || (b.name().toUpper().startsWith("MERACH-667-")) ||
|
||||
!b.name().compare(ftms_bike, Qt::CaseInsensitive) || (b.name().toUpper().startsWith("SMB1")) ||
|
||||
(b.name().toUpper().startsWith("UBIKE FTMS")) || (b.name().toUpper().startsWith("INRIDE"))) &&
|
||||
(b.name().toUpper().startsWith("DIRETO XR")) || (b.name().toUpper().startsWith("SMB1")) ||
|
||||
(b.name().toUpper().startsWith("INRIDE"))) &&
|
||||
!ftmsBike && !snodeBike && !fitPlusBike && !stagesBike && filter) {
|
||||
this->setLastBluetoothDevice(b);
|
||||
this->stopDiscovery();
|
||||
@@ -1370,7 +1349,6 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) {
|
||||
this->signalBluetoothDeviceConnected(ftmsBike);
|
||||
} else if ((b.name().toUpper().startsWith("KICKR SNAP") || b.name().toUpper().startsWith("KICKR BIKE") ||
|
||||
b.name().toUpper().startsWith("KICKR ROLLR") ||
|
||||
(b.name().toUpper().startsWith("HAMMER ") && saris_trainer) ||
|
||||
(b.name().toUpper().startsWith("WAHOO KICKR"))) &&
|
||||
!wahooKickrSnapBike && filter) {
|
||||
this->setLastBluetoothDevice(b);
|
||||
@@ -1399,7 +1377,6 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) {
|
||||
horizonGr7Bike->deviceDiscovered(b);
|
||||
this->signalBluetoothDeviceConnected(horizonGr7Bike);
|
||||
} else if ((b.name().toUpper().startsWith(QStringLiteral("STAGES ")) ||
|
||||
(b.name().toUpper().startsWith(QStringLiteral("QD")) && b.name().length() == 2) ||
|
||||
(b.name().toUpper().startsWith(QStringLiteral("ASSIOMA")) &&
|
||||
powerSensorName.startsWith(QStringLiteral("Disabled")))) &&
|
||||
!stagesBike && !ftmsBike && filter) {
|
||||
@@ -1453,7 +1430,6 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) {
|
||||
b.name().toUpper().startsWith(QStringLiteral("KS-WLT")) || // KS-WLT-W1
|
||||
b.name().toUpper().startsWith(QStringLiteral("I-ROWER")) ||
|
||||
b.name().toUpper().startsWith(QStringLiteral("SF-RW")) ||
|
||||
b.name().toUpper().startsWith(QStringLiteral("DFIT-L-R")) ||
|
||||
!b.name().compare(ftms_rower, Qt::CaseInsensitive) ||
|
||||
(b.name().toUpper().startsWith(QStringLiteral("PM5")) &&
|
||||
b.name().toUpper().endsWith(QStringLiteral("ROW")))) &&
|
||||
@@ -1472,7 +1448,6 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) {
|
||||
this->signalBluetoothDeviceConnected(ftmsRower);
|
||||
} else if ((b.name().toUpper().startsWith(QLatin1String("ECH-STRIDE")) ||
|
||||
b.name().toUpper().startsWith(QLatin1String("ECH-UK-")) ||
|
||||
b.name().toUpper().startsWith(QLatin1String("ECH-FR-")) ||
|
||||
b.name().toUpper().startsWith(QLatin1String("ECH-SD-SPT"))) &&
|
||||
!echelonStride && filter) {
|
||||
this->setLastBluetoothDevice(b);
|
||||
@@ -1806,8 +1781,7 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) {
|
||||
// SLOT(inclinationChanged(double)));
|
||||
mcfBike->deviceDiscovered(b);
|
||||
this->signalBluetoothDeviceConnected(mcfBike);
|
||||
} else if ((b.name().startsWith(QStringLiteral("TRX ROUTE KEY")) ||
|
||||
b.name().toUpper().startsWith(QStringLiteral("BH-TR-"))) && !toorx && filter) {
|
||||
} else if ((b.name().startsWith(QStringLiteral("TRX ROUTE KEY"))) && !toorx && filter) {
|
||||
this->setLastBluetoothDevice(b);
|
||||
this->stopDiscovery();
|
||||
toorx = new toorxtreadmill();
|
||||
@@ -1876,7 +1850,6 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) {
|
||||
(b.name().toUpper().startsWith(QStringLiteral("ICONSOLE+"))) ||
|
||||
(b.name().toUpper().startsWith(QStringLiteral("I-RUNNING"))) ||
|
||||
(b.name().toUpper().startsWith(QStringLiteral("DKN RUN"))) ||
|
||||
(b.name().toUpper().startsWith(QStringLiteral("ADIDAS "))) ||
|
||||
(b.name().toUpper().startsWith(QStringLiteral("REEBOK")))) &&
|
||||
!trxappgateusb && !trxappgateusbBike && !toorx_bike && !toorx_ftms && !toorx_ftms_treadmill &&
|
||||
filter) {
|
||||
@@ -1891,8 +1864,6 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) {
|
||||
trxappgateusb->deviceDiscovered(b);
|
||||
this->signalBluetoothDeviceConnected(trxappgateusb);
|
||||
} else if ((b.name().toUpper().startsWith(QStringLiteral("TUN ")) ||
|
||||
b.name().toUpper().startsWith(QStringLiteral("FITHIWAY")) ||
|
||||
b.name().toUpper().startsWith(QStringLiteral("FIT HI WAY")) ||
|
||||
((b.name().startsWith(QStringLiteral("TOORX")) ||
|
||||
b.name().toUpper().startsWith(QStringLiteral("I-CONSOIE+")) ||
|
||||
b.name().toUpper().startsWith(QStringLiteral("I-CONSOLE+")) ||
|
||||
@@ -1963,7 +1934,6 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) {
|
||||
skandikaWiriBike->deviceDiscovered(b);
|
||||
this->signalBluetoothDeviceConnected(skandikaWiriBike);
|
||||
} else if (((b.name().toUpper().startsWith("RQ") && b.name().length() == 5) ||
|
||||
(b.name().toUpper().startsWith("R-Q") && b.name().length() > 6) ||
|
||||
(b.name().toUpper().startsWith("SCH130")) || // not a renpho bike an FTMS one
|
||||
((b.name().startsWith(QStringLiteral("TOORX"))) && toorx_ftms && !toorx_ftms_treadmill)) &&
|
||||
!renphoBike && !snodeBike && !fitPlusBike && filter) {
|
||||
@@ -2016,13 +1986,13 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) {
|
||||
// connect(fitPlusBike, SIGNAL(debug(QString)), this, SLOT(debug(QString)));
|
||||
fitPlusBike->deviceDiscovered(b);
|
||||
this->signalBluetoothDeviceConnected(fitPlusBike);
|
||||
} else if (((b.name().startsWith(QStringLiteral("FS-")) && !horizonTreadmill && !snode_bike && !fitplus_bike && !ftmsBike && !iconsole_elliptical) ||
|
||||
} else if (((b.name().startsWith(QStringLiteral("FS-")) && !snode_bike && !fitplus_bike && !ftmsBike) ||
|
||||
b.name().toUpper().startsWith(QStringLiteral("NOBLEPRO CONNECT")) || // FTMS
|
||||
(b.name().startsWith(QStringLiteral("SW")) && b.name().length() == 14 &&
|
||||
!b.name().contains('(') && !b.name().contains(')')) ||
|
||||
(b.name().toUpper().startsWith(QStringLiteral("WINFITA"))) || // also FTMS
|
||||
(b.name().startsWith(QStringLiteral("BF70")))) &&
|
||||
!fitshowTreadmill && !iconsole_elliptical && filter) {
|
||||
!fitshowTreadmill && filter) {
|
||||
this->setLastBluetoothDevice(b);
|
||||
this->stopDiscovery();
|
||||
fitshowTreadmill = new fitshowtreadmill(this->pollDeviceTime, noConsole, noHeartService);
|
||||
@@ -2232,16 +2202,6 @@ void bluetooth::connectedAndDiscovered() {
|
||||
f->deviceDiscovered(b);
|
||||
wahookickrHeadWind.append(f);
|
||||
break;
|
||||
} else if (((b.name().toUpper().startsWith("ARIA")) && b.name().length() == 4) && !fitmetria_fanfit_isconnected(b.name())) {
|
||||
eliteariafan *f = new eliteariafan(this->device());
|
||||
|
||||
connect(f, &eliteariafan::debug, this, &bluetooth::debug);
|
||||
|
||||
connect(this->device(), SIGNAL(fanSpeedChanged(uint8_t)), f, SLOT(fanSpeedRequest(uint8_t)));
|
||||
|
||||
f->deviceDiscovered(b);
|
||||
eliteAriaFan.append(f);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2364,12 +2324,10 @@ void bluetooth::connectedAndDiscovered() {
|
||||
QAndroidJniObject activity = QAndroidJniObject::callStaticObjectMethod("org/qtproject/qt5/android/QtNative",
|
||||
"activity", "()Landroid/app/Activity;");
|
||||
KeepAwakeHelper::antObject(true)->callMethod<void>(
|
||||
"antStart", "(Landroid/app/Activity;ZZZZ)V", activity.object<jobject>(),
|
||||
"antStart", "(Landroid/app/Activity;ZZZ)V", activity.object<jobject>(),
|
||||
settings.value(QZSettings::ant_cadence, QZSettings::default_ant_cadence).toBool(),
|
||||
settings.value(QZSettings::ant_heart, QZSettings::default_ant_heart).toBool(),
|
||||
settings.value(QZSettings::ant_garmin, QZSettings::default_ant_garmin).toBool(),
|
||||
device()->deviceType() == bluetoothdevice::TREADMILL ||
|
||||
device()->deviceType() == bluetoothdevice::ELLIPTICAL);
|
||||
settings.value(QZSettings::ant_garmin, QZSettings::default_ant_garmin).toBool());
|
||||
}
|
||||
|
||||
if (settings.value(QZSettings::android_notification, QZSettings::default_android_notification).toBool()) {
|
||||
@@ -2568,11 +2526,6 @@ void bluetooth::restart() {
|
||||
delete proformWifiBike;
|
||||
proformWifiBike = nullptr;
|
||||
}
|
||||
if (proformTelnetBike) {
|
||||
|
||||
delete proformTelnetBike;
|
||||
proformTelnetBike = nullptr;
|
||||
}
|
||||
if (proformWifiTreadmill) {
|
||||
|
||||
delete proformWifiTreadmill;
|
||||
@@ -2919,14 +2872,6 @@ void bluetooth::restart() {
|
||||
}
|
||||
wahookickrHeadWind.clear();
|
||||
}
|
||||
if (eliteAriaFan.length()) {
|
||||
|
||||
foreach (eliteariafan *f, eliteAriaFan) {
|
||||
delete f;
|
||||
f = nullptr;
|
||||
}
|
||||
eliteAriaFan.clear();
|
||||
}
|
||||
if (cadenceSensor) {
|
||||
|
||||
// heartRateBelt->disconnectBluetooth(); // to test
|
||||
@@ -2986,8 +2931,6 @@ bluetoothdevice *bluetooth::device() {
|
||||
return cscBike;
|
||||
} else if (proformWifiBike) {
|
||||
return proformWifiBike;
|
||||
} else if (proformTelnetBike) {
|
||||
return proformTelnetBike;
|
||||
} else if (proformWifiTreadmill) {
|
||||
return proformWifiTreadmill;
|
||||
} else if (nordictrackifitadbTreadmill) {
|
||||
@@ -3257,10 +3200,6 @@ bool bluetooth::fitmetria_fanfit_isconnected(QString name) {
|
||||
if (!name.compare(f->bluetoothDevice.name()))
|
||||
return true;
|
||||
}
|
||||
foreach (eliteariafan *f, eliteAriaFan) {
|
||||
if (!name.compare(f->bluetoothDevice.name()))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -41,7 +41,6 @@
|
||||
|
||||
#include "echelonconnectsport.h"
|
||||
#include "echelonrower.h"
|
||||
#include "eliteariafan.h"
|
||||
#include "eliterizer.h"
|
||||
#include "elitesterzosmart.h"
|
||||
#include "eslinkertreadmill.h"
|
||||
@@ -86,7 +85,6 @@
|
||||
#include "proformellipticaltrainer.h"
|
||||
#include "proformrower.h"
|
||||
#include "proformtreadmill.h"
|
||||
#include "proformtelnetbike.h"
|
||||
#include "proformwifibike.h"
|
||||
#include "proformwifitreadmill.h"
|
||||
#include "schwinn170bike.h"
|
||||
@@ -188,7 +186,6 @@ class bluetooth : public QObject, public SignalHandler {
|
||||
pelotonbike *pelotonBike = nullptr;
|
||||
proformrower *proformRower = nullptr;
|
||||
proformbike *proformBike = nullptr;
|
||||
proformtelnetbike *proformTelnetBike = nullptr;
|
||||
proformwifibike *proformWifiBike = nullptr;
|
||||
proformwifitreadmill *proformWifiTreadmill = nullptr;
|
||||
proformelliptical *proformElliptical = nullptr;
|
||||
@@ -253,7 +250,6 @@ class bluetooth : public QObject, public SignalHandler {
|
||||
faketreadmill *fakeTreadmill = nullptr;
|
||||
QList<fitmetria_fanfit *> fitmetriaFanfit;
|
||||
QList<wahookickrheadwind *> wahookickrHeadWind;
|
||||
QList<eliteariafan *> eliteAriaFan;
|
||||
QString filterDevice = QLatin1String("");
|
||||
|
||||
bool testResistance = false;
|
||||
|
||||
@@ -247,15 +247,9 @@ void bluetoothdevice::update_hr_from_external() {
|
||||
long appleWatchHeartRate = h.heartRate();
|
||||
h.setKcal(KCal.value());
|
||||
h.setDistance(Distance.value());
|
||||
h.setSpeed(Speed.value());
|
||||
h.setPower(m_watt.value());
|
||||
h.setCadence(Cadence.value());
|
||||
Heart = appleWatchHeartRate;
|
||||
qDebug() << "Current Heart from Apple Watch: " << QString::number(appleWatchHeartRate);
|
||||
#endif
|
||||
#endif
|
||||
#ifdef Q_OS_ANDROID
|
||||
Heart = QAndroidJniObject::callStaticMethod<jint>("org/cagnulen/qdomyoszwift/WearableController", "getHeart", "()I");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -267,7 +261,6 @@ void bluetoothdevice::clearStats() {
|
||||
Speed.clear(false);
|
||||
KCal.clear(true);
|
||||
Distance.clear(true);
|
||||
Distance1s.clear(true);
|
||||
Heart.clear(false);
|
||||
m_jouls.clear(true);
|
||||
elevationAcc = 0;
|
||||
@@ -285,7 +278,6 @@ void bluetoothdevice::setPaused(bool p) {
|
||||
Speed.setPaused(p);
|
||||
KCal.setPaused(p);
|
||||
Distance.setPaused(p);
|
||||
Distance1s.setPaused(p);
|
||||
Heart.setPaused(p);
|
||||
m_jouls.setPaused(p);
|
||||
m_watt.setPaused(p);
|
||||
@@ -301,7 +293,6 @@ void bluetoothdevice::setLap() {
|
||||
Speed.setLap(false);
|
||||
KCal.setLap(true);
|
||||
Distance.setLap(true);
|
||||
Distance1s.setLap(true);
|
||||
Heart.setLap(false);
|
||||
m_jouls.setLap(true);
|
||||
m_watt.setLap(false);
|
||||
|
||||
@@ -100,9 +100,6 @@ class bluetoothdevice : public QObject {
|
||||
* @return
|
||||
*/
|
||||
virtual double odometer();
|
||||
virtual metric currentDistance() {return Distance;}
|
||||
virtual metric currentDistance1s() {return Distance1s;}
|
||||
void addCurrentDistance1s(double distance) { Distance1s += distance; }
|
||||
|
||||
/**
|
||||
* @brief calories Gets a metric object to get and set the amount of energy expended.
|
||||
@@ -498,7 +495,6 @@ class bluetoothdevice : public QObject {
|
||||
* the length of belt traversed on a treadmill.
|
||||
*/
|
||||
metric Distance;
|
||||
metric Distance1s; // used to populate the distance on the FIT file. Since Strava is using the distance to graph it, it has to have 1s trigger.
|
||||
|
||||
/**
|
||||
* @brief FanSpeed The currently requested fan speed. Units: revolutions per second
|
||||
|
||||
@@ -6,15 +6,18 @@ CharacteristicNotifier2A53::CharacteristicNotifier2A53(bluetoothdevice *Bike, QO
|
||||
|
||||
int CharacteristicNotifier2A53::notify(QByteArray &value) {
|
||||
bluetoothdevice::BLUETOOTH_TYPE dt = Bike->deviceType();
|
||||
value.append(0x02); // total distance
|
||||
uint16_t speed = Bike->currentSpeed().value() / 3.6 * 256;
|
||||
uint32_t distance = Bike->odometer() * 10000.0;
|
||||
value.append((char)((speed & 0xFF)));
|
||||
value.append((char)((speed >> 8) & 0xFF));
|
||||
value.append((char)(Bike->currentCadence().value()));
|
||||
value.append((char)((distance & 0xFF)));
|
||||
value.append((char)((distance >> 8) & 0xFF));
|
||||
value.append((char)((distance >> 16) & 0xFF));
|
||||
value.append((char)((distance >> 24) & 0xFF));
|
||||
return CN_OK;
|
||||
if (dt == bluetoothdevice::TREADMILL || dt == bluetoothdevice::ELLIPTICAL) {
|
||||
value.append(0x02); // total distance
|
||||
uint16_t speed = Bike->currentSpeed().value() / 3.6 * 256;
|
||||
uint32_t distance = Bike->odometer() * 10000.0;
|
||||
value.append((char)((speed & 0xFF)));
|
||||
value.append((char)((speed >> 8) & 0xFF));
|
||||
value.append((char)(Bike->currentCadence().value()));
|
||||
value.append((char)((distance & 0xFF)));
|
||||
value.append((char)((distance >> 8) & 0xFF));
|
||||
value.append((char)((distance >> 16) & 0xFF));
|
||||
value.append((char)((distance >> 24) & 0xFF));
|
||||
return CN_OK;
|
||||
} else
|
||||
return CN_INVALID;
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ int CharacteristicNotifier2ACC::notify(QByteArray &value) {
|
||||
value.append((char)0x14); // heart rate and elapsed time
|
||||
value.append((char)0x00);
|
||||
value.append((char)0x00);
|
||||
value.append((char)0x0F); // resistance, power, speed and inclination target supported
|
||||
value.append((char)0x0C); // resistance and power target supported
|
||||
value.append((char)0xE0); // indoor simulation, wheel and spin down supported
|
||||
value.append((char)0x00);
|
||||
value.append((char)0x00);
|
||||
|
||||
@@ -8,7 +8,7 @@ CharacteristicNotifier2ACD::CharacteristicNotifier2ACD(bluetoothdevice *Bike, QO
|
||||
int CharacteristicNotifier2ACD::notify(QByteArray &value) {
|
||||
bluetoothdevice::BLUETOOTH_TYPE dt = Bike->deviceType();
|
||||
if (dt == bluetoothdevice::TREADMILL || dt == bluetoothdevice::ELLIPTICAL) {
|
||||
value.append(0x0C); // Inclination available and distance for peloton
|
||||
value.append(0x08); // Inclination available
|
||||
value.append((char)0x01); // heart rate available
|
||||
|
||||
uint16_t normalizeSpeed = (uint16_t)qRound(Bike->currentSpeed().value() * 100);
|
||||
@@ -17,17 +17,6 @@ int CharacteristicNotifier2ACD::notify(QByteArray &value) {
|
||||
QByteArray speedBytes;
|
||||
speedBytes.append(b);
|
||||
speedBytes.append(a);
|
||||
|
||||
uint16_t normalizeDistance = (uint16_t)qRound(Bike->odometer() * 1000);
|
||||
a = (normalizeDistance >> 16) & 0XFF;
|
||||
b = (normalizeDistance >> 8) & 0XFF;
|
||||
char c = normalizeDistance & 0XFF;
|
||||
QByteArray distanceBytes;
|
||||
distanceBytes.append(c);
|
||||
distanceBytes.append(b);
|
||||
distanceBytes.append(a);
|
||||
|
||||
|
||||
uint16_t normalizeIncline = 0;
|
||||
if (dt == bluetoothdevice::TREADMILL)
|
||||
normalizeIncline = (uint32_t)qRound(((treadmill *)Bike)->currentInclination().value() * 10);
|
||||
@@ -47,8 +36,6 @@ int CharacteristicNotifier2ACD::notify(QByteArray &value) {
|
||||
rampBytes.append(a);
|
||||
|
||||
value.append(speedBytes); // Actual value.
|
||||
|
||||
value.append(distanceBytes); // Actual value.
|
||||
|
||||
value.append(inclineBytes); // incline
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
#include "characteristicnotifier2ad2.h"
|
||||
#include "elliptical.h"
|
||||
#include "rower.h"
|
||||
#include "treadmill.h"
|
||||
#include <QSettings>
|
||||
|
||||
@@ -9,17 +8,11 @@ CharacteristicNotifier2AD2::CharacteristicNotifier2AD2(bluetoothdevice *Bike, QO
|
||||
|
||||
int CharacteristicNotifier2AD2::notify(QByteArray &value) {
|
||||
bluetoothdevice::BLUETOOTH_TYPE dt = Bike->deviceType();
|
||||
|
||||
QSettings settings;
|
||||
bool virtual_device_rower =
|
||||
settings.value(QZSettings::virtual_device_rower, QZSettings::default_virtual_device_rower).toBool();
|
||||
bool rowerAsABike = !virtual_device_rower && dt == bluetoothdevice::ROWING;
|
||||
|
||||
double normalizeWattage = Bike->wattsMetric().value();
|
||||
if (normalizeWattage < 0)
|
||||
normalizeWattage = 0;
|
||||
|
||||
if (dt == bluetoothdevice::BIKE || rowerAsABike) {
|
||||
if (dt == bluetoothdevice::BIKE) {
|
||||
uint16_t normalizeSpeed = (uint16_t)qRound(Bike->currentSpeed().value() * 100);
|
||||
value.append((char)0x64); // speed, inst. cadence, resistance lvl, instant power
|
||||
value.append((char)0x02); // heart rate
|
||||
@@ -39,7 +32,7 @@ int CharacteristicNotifier2AD2::notify(QByteArray &value) {
|
||||
value.append(char(Bike->currentHeart().value())); // Actual value.
|
||||
value.append((char)0); // Bkool FTMS protocol HRM offset 1280 fix
|
||||
return CN_OK;
|
||||
} else if (dt == bluetoothdevice::TREADMILL || dt == bluetoothdevice::ELLIPTICAL || dt == bluetoothdevice::ROWING) {
|
||||
} else if (dt == bluetoothdevice::TREADMILL || dt == bluetoothdevice::ELLIPTICAL) {
|
||||
QSettings settings;
|
||||
bool double_cadence = settings.value(QZSettings::powr_sensor_running_cadence_double, QZSettings::default_powr_sensor_running_cadence_double).toBool();
|
||||
double cadence_multiplier = 2.0;
|
||||
@@ -57,8 +50,6 @@ int CharacteristicNotifier2AD2::notify(QByteArray &value) {
|
||||
cadence = ((elliptical *)Bike)->currentCadence().value();
|
||||
else if (dt == bluetoothdevice::TREADMILL)
|
||||
cadence = ((treadmill *)Bike)->currentCadence().value();
|
||||
else if (dt == bluetoothdevice::ROWING)
|
||||
cadence = ((rower *)Bike)->currentCadence().value();
|
||||
|
||||
value.append((char)((uint16_t)(cadence * cadence_multiplier) & 0xFF)); // cadence
|
||||
value.append((char)(((uint16_t)(cadence * cadence_multiplier) >> 8) & 0xFF)); // cadence
|
||||
|
||||
@@ -126,7 +126,6 @@ void chronobike::serviceDiscovered(const QBluetoothUuid &gatt) {
|
||||
}
|
||||
|
||||
void chronobike::characteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &newValue) {
|
||||
QDateTime now = QDateTime::currentDateTime();
|
||||
// qDebug() << "characteristicChanged" << characteristic.uuid() << newValue << newValue.length();
|
||||
Q_UNUSED(characteristic);
|
||||
QSettings settings;
|
||||
@@ -154,7 +153,7 @@ void chronobike::characteristicChanged(const QLowEnergyCharacteristic &character
|
||||
} else {
|
||||
Speed = metric::calculateSpeedFromPower(
|
||||
watts(), Inclination.value(), Speed.value(),
|
||||
fabs(now.msecsTo(Speed.lastChanged()) / 1000.0), this->speedLimit());
|
||||
fabs(QDateTime::currentDateTime().msecsTo(Speed.lastChanged()) / 1000.0), this->speedLimit());
|
||||
}
|
||||
if (watts())
|
||||
KCal +=
|
||||
@@ -162,10 +161,10 @@ void chronobike::characteristicChanged(const QLowEnergyCharacteristic &character
|
||||
settings.value(QZSettings::weight, QZSettings::default_weight).toFloat() * 3.5) /
|
||||
200.0) /
|
||||
(60000.0 / ((double)lastRefreshCharacteristicChanged.msecsTo(
|
||||
now)))); //(( (0.048* Output in watts +1.19) * body weight in kg
|
||||
QDateTime::currentDateTime())))); //(( (0.048* Output in watts +1.19) * body weight in kg
|
||||
//* 3.5) / 200 ) / 60
|
||||
Distance += ((Speed.value() / 3600000.0) *
|
||||
((double)lastRefreshCharacteristicChanged.msecsTo(now)));
|
||||
((double)lastRefreshCharacteristicChanged.msecsTo(QDateTime::currentDateTime())));
|
||||
|
||||
double ac = 0.01243107769;
|
||||
double bc = 1.145964912;
|
||||
@@ -191,7 +190,7 @@ void chronobike::characteristicChanged(const QLowEnergyCharacteristic &character
|
||||
LastCrankEventTime += (uint16_t)(1024.0 / (((double)(Cadence.value())) / 60.0));
|
||||
}
|
||||
|
||||
lastRefreshCharacteristicChanged = now;
|
||||
lastRefreshCharacteristicChanged = QDateTime::currentDateTime();
|
||||
|
||||
#ifdef Q_OS_ANDROID
|
||||
if (settings.value(QZSettings::ant_heart, QZSettings::default_ant_heart).toBool())
|
||||
|
||||
@@ -131,7 +131,6 @@ void concept2skierg::serviceDiscovered(const QBluetoothUuid &gatt) {
|
||||
}
|
||||
|
||||
void concept2skierg::characteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &newValue) {
|
||||
QDateTime now = QDateTime::currentDateTime();
|
||||
|
||||
// qDebug() << "characteristicChanged" << characteristic.uuid() << newValue << newValue.length();
|
||||
Q_UNUSED(characteristic);
|
||||
@@ -173,7 +172,7 @@ void concept2skierg::characteristicChanged(const QLowEnergyCharacteristic &chara
|
||||
break;
|
||||
case 0x32:
|
||||
qDebug() << "32";
|
||||
if (newValue.length() >= 19) {
|
||||
if (newValue.length() >= 20) {
|
||||
// 0.001 m/s
|
||||
uint16_t speed_ms = (((uint16_t)((uint16_t)newValue.at(5)) << 8) | (uint16_t)((uint8_t)newValue.at(4)));
|
||||
uint8_t stroke_rate = newValue.at(6);
|
||||
@@ -239,7 +238,7 @@ void concept2skierg::characteristicChanged(const QLowEnergyCharacteristic &chara
|
||||
LastCrankEventTime += (uint16_t)(1024.0 / (((double)(Cadence.value())) / 60.0));
|
||||
}
|
||||
|
||||
lastRefreshCharacteristicChanged = now;
|
||||
lastRefreshCharacteristicChanged = QDateTime::currentDateTime();
|
||||
|
||||
if (heartRateBeltName.startsWith(QStringLiteral("Disabled"))) {
|
||||
update_hr_from_external();
|
||||
|
||||
@@ -182,7 +182,61 @@ int csaferowerThread::openPort() {
|
||||
|
||||
tcflush(devicePort, TCIOFLUSH); // clear out the garbage
|
||||
#else
|
||||
// WINDOWS USES SET/GETCOMMSTATE AND READ/WRITEFILE
|
||||
|
||||
COMMTIMEOUTS timeouts; // timeout settings on serial ports
|
||||
|
||||
// if deviceFilename references a port above COM9
|
||||
// then we need to open "\\.\COMX" not "COMX"
|
||||
QString portSpec;
|
||||
int portnum = deviceFilename.midRef(3).toString().toInt();
|
||||
if (portnum < 10)
|
||||
portSpec = deviceFilename;
|
||||
else
|
||||
portSpec = "\\\\.\\" + deviceFilename;
|
||||
wchar_t deviceFilenameW[32]; // \\.\COM32 needs 9 characters, 32 should be enough?
|
||||
MultiByteToWideChar(CP_ACP, 0, portSpec.toLatin1(), -1, (LPWSTR)deviceFilenameW, sizeof(deviceFilenameW));
|
||||
|
||||
// win32 commport API
|
||||
devicePort = CreateFile(deviceFilenameW, GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_DELETE | FILE_SHARE_WRITE | FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
|
||||
|
||||
if (devicePort == INVALID_HANDLE_VALUE)
|
||||
return -1;
|
||||
|
||||
if (GetCommState(devicePort, &deviceSettings) == false)
|
||||
return -1;
|
||||
|
||||
// so we've opened the comm port lets set it up for
|
||||
deviceSettings.BaudRate = CBR_2400;
|
||||
deviceSettings.fParity = NOPARITY;
|
||||
deviceSettings.ByteSize = 8;
|
||||
deviceSettings.StopBits = ONESTOPBIT;
|
||||
deviceSettings.XonChar = 11;
|
||||
deviceSettings.XoffChar = 13;
|
||||
deviceSettings.EofChar = 0x0;
|
||||
deviceSettings.ErrorChar = 0x0;
|
||||
deviceSettings.EvtChar = 0x0;
|
||||
deviceSettings.fBinary = true;
|
||||
deviceSettings.fOutX = 0;
|
||||
deviceSettings.fInX = 0;
|
||||
deviceSettings.XonLim = 0;
|
||||
deviceSettings.XoffLim = 0;
|
||||
deviceSettings.fRtsControl = RTS_CONTROL_ENABLE;
|
||||
deviceSettings.fDtrControl = DTR_CONTROL_ENABLE;
|
||||
deviceSettings.fOutxCtsFlow = FALSE; // TRUE;
|
||||
|
||||
if (SetCommState(devicePort, &deviceSettings) == false) {
|
||||
CloseHandle(devicePort);
|
||||
return -1;
|
||||
}
|
||||
|
||||
timeouts.ReadIntervalTimeout = 0;
|
||||
timeouts.ReadTotalTimeoutConstant = 1000;
|
||||
timeouts.ReadTotalTimeoutMultiplier = 50;
|
||||
timeouts.WriteTotalTimeoutConstant = 2000;
|
||||
timeouts.WriteTotalTimeoutMultiplier = 0;
|
||||
SetCommTimeouts(devicePort, &timeouts);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -337,19 +391,17 @@ void csaferower::update() {
|
||||
} else
|
||||
#endif
|
||||
#endif
|
||||
{
|
||||
if (virtual_device_enabled) {
|
||||
if (!virtual_device_rower) {
|
||||
qDebug() << QStringLiteral("creating virtual bike interface...");
|
||||
auto virtualBike = new virtualbike(this, noWriteResistance, noHeartService);
|
||||
// connect(virtualBike,&virtualbike::debug ,this,&echelonrower::debug);
|
||||
this->setVirtualDevice(virtualBike, VIRTUAL_DEVICE_MODE::PRIMARY);
|
||||
} else {
|
||||
qDebug() << QStringLiteral("creating virtual rower interface...");
|
||||
auto virtualRower = new virtualrower(this, noWriteResistance, noHeartService);
|
||||
// connect(virtualRower,&virtualrower::debug ,this,&echelonrower::debug);
|
||||
this->setVirtualDevice(virtualRower, VIRTUAL_DEVICE_MODE::PRIMARY);
|
||||
}
|
||||
if (!virtual_device_rower) {
|
||||
qDebug() << QStringLiteral("creating virtual bike interface...");
|
||||
auto virtualBike = new virtualbike(this, noWriteResistance, noHeartService);
|
||||
// connect(virtualBike,&virtualbike::debug ,this,&echelonrower::debug);
|
||||
this->setVirtualDevice(virtualBike, VIRTUAL_DEVICE_MODE::PRIMARY);
|
||||
} else {
|
||||
qDebug() << QStringLiteral("creating virtual rower interface...");
|
||||
auto virtualRower = new virtualrower(this, noWriteResistance, noHeartService);
|
||||
// connect(virtualRower,&virtualrower::debug ,this,&echelonrower::debug);
|
||||
this->setVirtualDevice(virtualRower, VIRTUAL_DEVICE_MODE::PRIMARY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,9 +37,12 @@
|
||||
#include <QThread>
|
||||
|
||||
#ifdef WIN32
|
||||
#include <windows.h>
|
||||
#include <windef.h>
|
||||
#endif
|
||||
|
||||
#ifdef WIN32
|
||||
#include <winbase.h>
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <sys/ioctl.h>
|
||||
#include <termios.h> // unix!!
|
||||
|
||||
@@ -89,15 +89,6 @@ void cscbike::update() {
|
||||
/*initDone*/) {
|
||||
update_metrics(true, watts());
|
||||
|
||||
if(lastGoodCadence.secsTo(QDateTime::currentDateTime()) > 5 && !charNotified) {
|
||||
readMethod = true;
|
||||
qDebug() << "no cadence for 5 secs, switching to reading method";
|
||||
}
|
||||
|
||||
if(readMethod && cadenceService) {
|
||||
cadenceService->readCharacteristic(cadenceChar);
|
||||
}
|
||||
|
||||
// updating the treadmill console every second
|
||||
if (sec1Update++ == (500 / refresh->interval())) {
|
||||
sec1Update = 0;
|
||||
@@ -138,7 +129,6 @@ void cscbike::serviceDiscovered(const QBluetoothUuid &gatt) {
|
||||
}
|
||||
|
||||
void cscbike::characteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &newValue) {
|
||||
QDateTime now = QDateTime::currentDateTime();
|
||||
// qDebug() << "characteristicChanged" << characteristic.uuid() << newValue << newValue.length();
|
||||
Q_UNUSED(characteristic);
|
||||
QSettings settings;
|
||||
@@ -151,8 +141,6 @@ void cscbike::characteristicChanged(const QLowEnergyCharacteristic &characterist
|
||||
double _WheelRevs = 0;
|
||||
uint8_t battery = 0;
|
||||
|
||||
charNotified = true;
|
||||
|
||||
emit debug(QStringLiteral(" << ") + newValue.toHex(' '));
|
||||
|
||||
if (characteristic.uuid() == QBluetoothUuid((quint16)0x2A19)) {
|
||||
@@ -212,8 +200,8 @@ void cscbike::characteristicChanged(const QLowEnergyCharacteristic &characterist
|
||||
double cadence = ((CrankRevs - oldCrankRevs) / deltaT) * 1024 * 60;
|
||||
if (cadence >= 0 && cadence < 256)
|
||||
Cadence = cadence;
|
||||
lastGoodCadence = now;
|
||||
} else if (lastGoodCadence.msecsTo(now) > 2000) {
|
||||
lastGoodCadence = QDateTime::currentDateTime();
|
||||
} else if (lastGoodCadence.msecsTo(QDateTime::currentDateTime()) > 2000) {
|
||||
Cadence = 0;
|
||||
}
|
||||
emit cadenceChanged(Cadence.value());
|
||||
@@ -229,12 +217,12 @@ void cscbike::characteristicChanged(const QLowEnergyCharacteristic &characterist
|
||||
} else {
|
||||
Speed = metric::calculateSpeedFromPower(
|
||||
watts(), Inclination.value(), Speed.value(),
|
||||
fabs(now.msecsTo(Speed.lastChanged()) / 1000.0), this->speedLimit());
|
||||
fabs(QDateTime::currentDateTime().msecsTo(Speed.lastChanged()) / 1000.0), this->speedLimit());
|
||||
}
|
||||
emit debug(QStringLiteral("Current Speed: ") + QString::number(Speed.value()));
|
||||
|
||||
Distance += ((Speed.value() / 3600000.0) *
|
||||
((double)lastRefreshCharacteristicChanged.msecsTo(now)));
|
||||
((double)lastRefreshCharacteristicChanged.msecsTo(QDateTime::currentDateTime())));
|
||||
emit debug(QStringLiteral("Current Distance: ") + QString::number(Distance.value()));
|
||||
|
||||
double ac = 0.01243107769;
|
||||
@@ -267,7 +255,7 @@ void cscbike::characteristicChanged(const QLowEnergyCharacteristic &characterist
|
||||
settings.value(QZSettings::weight, QZSettings::default_weight).toFloat() * 3.5) /
|
||||
200.0) /
|
||||
(60000.0 / ((double)lastRefreshCharacteristicChanged.msecsTo(
|
||||
now)))); //(( (0.048* Output in watts +1.19) * body weight in kg
|
||||
QDateTime::currentDateTime())))); //(( (0.048* Output in watts +1.19) * body weight in kg
|
||||
//* 3.5) / 200 ) / 60
|
||||
emit debug(QStringLiteral("Current KCal: ") + QString::number(KCal.value()));
|
||||
|
||||
@@ -276,7 +264,7 @@ void cscbike::characteristicChanged(const QLowEnergyCharacteristic &characterist
|
||||
LastCrankEventTime += (uint16_t)(1024.0 / (((double)(Cadence.value())) / 60.0));
|
||||
}
|
||||
|
||||
lastRefreshCharacteristicChanged = now;
|
||||
lastRefreshCharacteristicChanged = QDateTime::currentDateTime();
|
||||
|
||||
if (!noVirtualDevice) {
|
||||
#ifdef Q_OS_IOS
|
||||
@@ -323,16 +311,8 @@ void cscbike::stateChanged(QLowEnergyService::ServiceState state) {
|
||||
|
||||
qDebug() << QStringLiteral("all services discovered!");
|
||||
|
||||
QBluetoothUuid CyclingSpeedAndCadence(QBluetoothUuid::CyclingSpeedAndCadence);
|
||||
|
||||
for (QLowEnergyService *s : qAsConst(gattCommunicationChannelService)) {
|
||||
if (s->state() == QLowEnergyService::ServiceDiscovered) {
|
||||
|
||||
if(s->serviceUuid() == CyclingSpeedAndCadence) {
|
||||
qDebug() << "CyclingSpeedAndCadence found";
|
||||
cadenceService = s;
|
||||
}
|
||||
|
||||
// establish hook into notifications
|
||||
connect(s, &QLowEnergyService::characteristicChanged, this, &cscbike::characteristicChanged);
|
||||
connect(s, &QLowEnergyService::characteristicWritten, this, &cscbike::characteristicWritten);
|
||||
@@ -347,11 +327,7 @@ void cscbike::stateChanged(QLowEnergyService::ServiceState state) {
|
||||
|
||||
auto characteristics_list = s->characteristics();
|
||||
for (const QLowEnergyCharacteristic &c : qAsConst(characteristics_list)) {
|
||||
if(c.uuid() == QBluetoothUuid((quint16)0x2A5B)) {
|
||||
qDebug() << "CyclingSpeedAndCadence char found";
|
||||
cadenceChar = c;
|
||||
}
|
||||
qDebug() << QStringLiteral("char uuid") << c.uuid() << QStringLiteral("handle") << c.handle() << QStringLiteral("properties") << c.properties();
|
||||
qDebug() << QStringLiteral("char uuid") << c.uuid() << QStringLiteral("handle") << c.handle();
|
||||
auto descriptors_list = c.descriptors();
|
||||
for (const QLowEnergyDescriptor &d : qAsConst(descriptors_list)) {
|
||||
qDebug() << QStringLiteral("descriptor uuid") << d.uuid() << QStringLiteral("handle") << d.handle();
|
||||
@@ -448,8 +424,6 @@ void cscbike::characteristicWritten(const QLowEnergyCharacteristic &characterist
|
||||
|
||||
void cscbike::characteristicRead(const QLowEnergyCharacteristic &characteristic, const QByteArray &newValue) {
|
||||
qDebug() << QStringLiteral("characteristicRead ") << characteristic.uuid() << newValue.toHex(' ');
|
||||
|
||||
characteristicChanged(characteristic, newValue);
|
||||
}
|
||||
|
||||
void cscbike::serviceScanDone(void) {
|
||||
|
||||
@@ -47,15 +47,13 @@ class cscbike : public bike {
|
||||
QTimer *refresh;
|
||||
|
||||
QList<QLowEnergyService *> gattCommunicationChannelService;
|
||||
QLowEnergyService* cadenceService = nullptr;
|
||||
QLowEnergyCharacteristic cadenceChar;
|
||||
// QLowEnergyCharacteristic gattNotify1Characteristic;
|
||||
|
||||
uint8_t sec1Update = 0;
|
||||
QByteArray lastPacket;
|
||||
QDateTime lastRefreshCharacteristicChanged = QDateTime::currentDateTime();
|
||||
QDateTime lastGoodCadence = QDateTime::currentDateTime();
|
||||
uint8_t firstStateChanged = 0;
|
||||
bool charNotified = false;
|
||||
|
||||
bool initDone = false;
|
||||
bool initRequest = false;
|
||||
@@ -64,8 +62,6 @@ class cscbike : public bike {
|
||||
bool noHeartService = false;
|
||||
bool noVirtualDevice = false;
|
||||
|
||||
bool readMethod = false;
|
||||
|
||||
uint16_t oldLastCrankEventTime = 0;
|
||||
uint16_t oldCrankRevs = 0;
|
||||
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
#include "dirconmanager.h"
|
||||
#include <QNetworkInterface>
|
||||
#include <QSettings>
|
||||
#include <chrono>
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
#define DM_MACHINE_TYPE_BIKE 1
|
||||
#define DM_MACHINE_TYPE_TREADMILL 2
|
||||
@@ -169,10 +166,7 @@ DirconManager::DirconManager(bluetoothdevice *Bike, uint8_t bikeResistanceOffset
|
||||
QObject::connect(&bikeTimer, &QTimer::timeout, this, &DirconManager::bikeProvider);
|
||||
QString mac = getMacAddress();
|
||||
DM_MACHINE_OP(DM_MACHINE_INIT_OP, services, proc_services, type)
|
||||
if (settings.value(QZSettings::race_mode, QZSettings::default_race_mode).toBool())
|
||||
bikeTimer.start(100ms);
|
||||
else
|
||||
bikeTimer.start(1s);
|
||||
bikeTimer.start(1000);
|
||||
}
|
||||
|
||||
#define DM_CHAR_NOTIF_NOTIF1_OP(UUID, P1, P2, P3) \
|
||||
|
||||
@@ -283,7 +283,6 @@ void domyosbike::serviceDiscovered(const QBluetoothUuid &gatt) {
|
||||
}
|
||||
|
||||
void domyosbike::characteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &newValue) {
|
||||
QDateTime now = QDateTime::currentDateTime();
|
||||
// qDebug() << "characteristicChanged" << characteristic.uuid() << newValue << newValue.length();
|
||||
Q_UNUSED(characteristic);
|
||||
QSettings settings;
|
||||
@@ -401,7 +400,7 @@ void domyosbike::characteristicChanged(const QLowEnergyCharacteristic &character
|
||||
CrankRevs++;
|
||||
LastCrankEventTime += (uint16_t)(1024.0 / (((double)(Cadence.value())) / 60.0));
|
||||
}
|
||||
lastRefreshCharacteristicChanged = now;
|
||||
lastRefreshCharacteristicChanged = QDateTime::currentDateTime();
|
||||
|
||||
#ifdef Q_OS_IOS
|
||||
#ifndef IO_UNDER_QT
|
||||
@@ -434,7 +433,7 @@ void domyosbike::characteristicChanged(const QLowEnergyCharacteristic &character
|
||||
} else {
|
||||
Speed = metric::calculateSpeedFromPower(
|
||||
watts(), Inclination.value(), Speed.value(),
|
||||
fabs(now.msecsTo(Speed.lastChanged()) / 1000.0), this->speedLimit());
|
||||
fabs(QDateTime::currentDateTime().msecsTo(Speed.lastChanged()) / 1000.0), this->speedLimit());
|
||||
}
|
||||
KCal = kcal;
|
||||
Distance = distance;
|
||||
|
||||
@@ -56,7 +56,8 @@ void domyosrower::writeCharacteristic(uint8_t *data, uint8_t data_len, const QSt
|
||||
gattCommunicationChannelService->writeCharacteristic(gattWriteCharacteristic, *writeBuffer);
|
||||
|
||||
if (!disable_log) {
|
||||
emit debug(QStringLiteral(" >> ") + writeBuffer->toHex(' ') + QStringLiteral(" // ") + info);
|
||||
emit debug(QStringLiteral(" >> ") + writeBuffer->toHex(' ') +
|
||||
QStringLiteral(" // ") + info);
|
||||
}
|
||||
|
||||
loop.exec();
|
||||
@@ -195,8 +196,7 @@ void domyosrower::update() {
|
||||
this->setVirtualDevice(virtualTreadmill, VIRTUAL_DEVICE_MODE::PRIMARY);
|
||||
} else {
|
||||
debug("creating virtual bike interface...");
|
||||
auto virtualBike = new virtualbike(this, noWriteResistance, noHeartService, bikeResistanceOffset,
|
||||
bikeResistanceGain);
|
||||
auto virtualBike = new virtualbike(this);
|
||||
connect(virtualBike, &virtualbike::changeInclination, this,
|
||||
&domyosrower::changeInclinationRequested);
|
||||
connect(virtualBike, &virtualbike::changeInclination, this, &domyosrower::changeInclination);
|
||||
@@ -274,7 +274,6 @@ void domyosrower::serviceDiscovered(const QBluetoothUuid &gatt) {
|
||||
}
|
||||
|
||||
void domyosrower::characteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &newValue) {
|
||||
QDateTime now = QDateTime::currentDateTime();
|
||||
// qDebug() << "characteristicChanged" << characteristic.uuid() << newValue << newValue.length();
|
||||
Q_UNUSED(characteristic);
|
||||
QSettings settings;
|
||||
@@ -361,16 +360,15 @@ void domyosrower::characteristicChanged(const QLowEnergyCharacteristic &characte
|
||||
Speed = speed;
|
||||
KCal = kcal;
|
||||
Distance += ((Speed.value() / 3600000.0) *
|
||||
((double)lastRefreshCharacteristicChanged.msecsTo(now)));
|
||||
lastRefreshCharacteristicChanged = now;
|
||||
((double)lastRefreshCharacteristicChanged.msecsTo(QDateTime::currentDateTime())));
|
||||
lastRefreshCharacteristicChanged = QDateTime::currentDateTime();
|
||||
}
|
||||
|
||||
double domyosrower::GetSpeedFromPacket(const QByteArray &packet) {
|
||||
|
||||
uint16_t convertedData = (packet.at(6) << 8) | packet.at(7);
|
||||
if (convertedData > 65000 || convertedData == 0 || currentCadence().value() == 0)
|
||||
return 0;
|
||||
return (60.0 / (double)(convertedData)) * 30.0;
|
||||
double data = (double)convertedData / 10.0f;
|
||||
return data;
|
||||
}
|
||||
|
||||
double domyosrower::GetKcalFromPacket(const QByteArray &packet) {
|
||||
|
||||
@@ -158,7 +158,7 @@ void echelonconnectsport::serviceDiscovered(const QBluetoothUuid &gatt) {
|
||||
|
||||
resistance_t echelonconnectsport::pelotonToBikeResistance(int pelotonResistance) {
|
||||
for (resistance_t i = 1; i < max_resistance; i++) {
|
||||
if (bikeResistanceToPeloton(i) <= pelotonResistance && bikeResistanceToPeloton(i + 1) > pelotonResistance) {
|
||||
if (bikeResistanceToPeloton(i) <= pelotonResistance && bikeResistanceToPeloton(i + 1) >= pelotonResistance) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
@@ -404,8 +404,6 @@ void echelonconnectsport::stateChanged(QLowEnergyService::ServiceState state) {
|
||||
QSettings settings;
|
||||
bool virtual_device_enabled =
|
||||
settings.value(QZSettings::virtual_device_enabled, QZSettings::default_virtual_device_enabled).toBool();
|
||||
bool virtual_device_rower =
|
||||
settings.value(QZSettings::virtual_device_rower, QZSettings::default_virtual_device_rower).toBool();
|
||||
#ifdef Q_OS_IOS
|
||||
#ifndef IO_UNDER_QT
|
||||
bool cadence =
|
||||
@@ -420,19 +418,12 @@ void echelonconnectsport::stateChanged(QLowEnergyService::ServiceState state) {
|
||||
#endif
|
||||
#endif
|
||||
if (virtual_device_enabled) {
|
||||
if (virtual_device_rower) {
|
||||
qDebug() << QStringLiteral("creating virtual rower interface...");
|
||||
auto virtualRower = new virtualrower(this, noWriteResistance, noHeartService);
|
||||
// connect(virtualRower,&virtualrower::debug ,this,&echelonrower::debug);
|
||||
this->setVirtualDevice(virtualRower, VIRTUAL_DEVICE_MODE::ALTERNATIVE);
|
||||
} else {
|
||||
qDebug() << QStringLiteral("creating virtual bike interface...");
|
||||
auto virtualBike =
|
||||
new virtualbike(this, noWriteResistance, noHeartService, bikeResistanceOffset, bikeResistanceGain);
|
||||
// connect(virtualBike,&virtualbike::debug ,this,&echelonconnectsport::debug);
|
||||
connect(virtualBike, &virtualbike::changeInclination, this, &echelonconnectsport::changeInclination);
|
||||
this->setVirtualDevice(virtualBike, VIRTUAL_DEVICE_MODE::PRIMARY);
|
||||
}
|
||||
qDebug() << QStringLiteral("creating virtual bike interface...");
|
||||
auto virtualBike =
|
||||
new virtualbike(this, noWriteResistance, noHeartService, bikeResistanceOffset, bikeResistanceGain);
|
||||
// connect(virtualBike,&virtualbike::debug ,this,&echelonconnectsport::debug);
|
||||
connect(virtualBike, &virtualbike::changeInclination, this, &echelonconnectsport::changeInclination);
|
||||
this->setVirtualDevice(virtualBike, VIRTUAL_DEVICE_MODE::PRIMARY);
|
||||
}
|
||||
}
|
||||
firstStateChanged = 1;
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
|
||||
#include "bike.h"
|
||||
#include "virtualbike.h"
|
||||
#include "virtualrower.h"
|
||||
|
||||
#ifdef Q_OS_IOS
|
||||
#include "ios/lockscreen.h"
|
||||
|
||||
@@ -25,7 +25,6 @@ echelonrower::echelonrower(bool noWriteResistance, bool noHeartService, uint8_t
|
||||
#endif
|
||||
m_watt.setType(metric::METRIC_WATT);
|
||||
Speed.setType(metric::METRIC_SPEED);
|
||||
speedRaw.setType(metric::METRIC_SPEED);
|
||||
refresh = new QTimer(this);
|
||||
this->noWriteResistance = noWriteResistance;
|
||||
this->noHeartService = noHeartService;
|
||||
@@ -237,13 +236,10 @@ void echelonrower::characteristicChanged(const QLowEnergyCharacteristic &charact
|
||||
((double)lastRefreshCharacteristicChanged.msecsTo(QDateTime::currentDateTime())) / 60000;
|
||||
}
|
||||
// instant pace to km/h
|
||||
if ((((uint8_t)lastPacket.at(14)) > 0 || ((uint8_t)lastPacket.at(13)) > 0) && Cadence.value() > 0) {
|
||||
speedRaw = (60.0 / (double)(((uint16_t)lastPacket.at(13) << 8) | ((uint16_t)lastPacket.at(14)))) * 30.0;
|
||||
Speed = speedRaw.average5s();
|
||||
} else {
|
||||
if (((uint8_t)lastPacket.at(14)) > 0)
|
||||
Speed = (60.0 / (double)((uint8_t)lastPacket.at(14))) * 30.0;
|
||||
else
|
||||
Speed = 0;
|
||||
speedRaw = 0;
|
||||
}
|
||||
|
||||
StrokesLength =
|
||||
((Speed.value() / 60.0) * 1000.0) /
|
||||
|
||||
@@ -76,7 +76,6 @@ class echelonrower : public rower {
|
||||
|
||||
bool noWriteResistance = false;
|
||||
bool noHeartService = false;
|
||||
metric speedRaw;
|
||||
|
||||
#ifdef Q_OS_IOS
|
||||
lockscreen *h = 0;
|
||||
|
||||
@@ -237,7 +237,6 @@ void echelonstride::serviceDiscovered(const QBluetoothUuid &gatt) {
|
||||
double echelonstride::minStepInclination() { return 1.0; }
|
||||
|
||||
void echelonstride::characteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &newValue) {
|
||||
QDateTime now = QDateTime::currentDateTime();
|
||||
// qDebug() << "characteristicChanged" << characteristic.uuid() << newValue << newValue.length();
|
||||
QSettings settings;
|
||||
QString heartRateBeltName =
|
||||
@@ -301,10 +300,10 @@ void echelonstride::characteristicChanged(const QLowEnergyCharacteristic &charac
|
||||
settings.value(QZSettings::weight, QZSettings::default_weight).toFloat() * 3.5) /
|
||||
200.0) /
|
||||
(60000.0 / ((double)lastTimeCharacteristicChanged.msecsTo(
|
||||
now)))); //(( (0.048* Output in watts +1.19) * body weight in
|
||||
QDateTime::currentDateTime())))); //(( (0.048* Output in watts +1.19) * body weight in
|
||||
// kg * 3.5) / 200 ) / 60
|
||||
Distance += ((Speed.value() / 3600.0) /
|
||||
(1000.0 / (lastTimeCharacteristicChanged.msecsTo(now))));
|
||||
(1000.0 / (lastTimeCharacteristicChanged.msecsTo(QDateTime::currentDateTime()))));
|
||||
}
|
||||
|
||||
if ((uint8_t)newValue.at(1) == 0xD1 && newValue.length() > 11)
|
||||
@@ -335,7 +334,7 @@ void echelonstride::characteristicChanged(const QLowEnergyCharacteristic &charac
|
||||
if (m_control->error() != QLowEnergyController::NoError)
|
||||
qDebug() << QStringLiteral("QLowEnergyController ERROR!!") << m_control->errorString();
|
||||
|
||||
lastTimeCharacteristicChanged = now;
|
||||
lastTimeCharacteristicChanged = QDateTime::currentDateTime();
|
||||
firstCharacteristicChanged = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,334 +0,0 @@
|
||||
#include "eliteariafan.h"
|
||||
#include <QBluetoothLocalDevice>
|
||||
#include <QDateTime>
|
||||
#include <QEventLoop>
|
||||
#include <QFile>
|
||||
#include <QMetaEnum>
|
||||
#include <QSettings>
|
||||
#include <QThread>
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
#ifdef Q_OS_IOS
|
||||
extern quint8 QZ_EnableDiscoveryCharsAndDescripttors;
|
||||
#endif
|
||||
|
||||
// this module on iOS is completely handled from the ObjectiveC module in order to test if it's more stable than the Qt Bluetooth Implementation (crash midride)
|
||||
|
||||
eliteariafan::eliteariafan(bluetoothdevice *parentDevice) {
|
||||
#ifdef Q_OS_IOS
|
||||
QZ_EnableDiscoveryCharsAndDescripttors = true;
|
||||
#endif
|
||||
this->parentDevice = parentDevice;
|
||||
|
||||
#ifndef Q_OS_IOS
|
||||
refresh = new QTimer(this);
|
||||
connect(refresh, &QTimer::timeout, this, &eliteariafan::update);
|
||||
refresh->start(1000ms);
|
||||
#endif
|
||||
}
|
||||
|
||||
void eliteariafan::update() {
|
||||
if (initRequest) {
|
||||
initRequest = false;
|
||||
|
||||
uint8_t init1[] = {0x02, 0x00, 0x00, 0x3d, 0x00};
|
||||
writeCharacteristic(gattWrite1Service, &gattWrite1Characteristic, init1, sizeof(init1), "init", false, true);
|
||||
|
||||
uint8_t init2[] = {0x05, 0x00};
|
||||
writeCharacteristic(gattWrite1Service, &gattWrite2Characteristic, init2, sizeof(init2), "init", false, true);
|
||||
|
||||
initDone = true;
|
||||
}
|
||||
}
|
||||
|
||||
void eliteariafan::serviceDiscovered(const QBluetoothUuid &gatt) {
|
||||
emit debug(QStringLiteral("serviceDiscovered ") + gatt.toString());
|
||||
}
|
||||
|
||||
void eliteariafan::disconnectBluetooth() {
|
||||
qDebug() << QStringLiteral("eliteariafan::disconnect") << m_control;
|
||||
|
||||
if (m_control) {
|
||||
m_control->disconnectFromDevice();
|
||||
}
|
||||
}
|
||||
|
||||
void eliteariafan::characteristicChanged(const QLowEnergyCharacteristic &characteristic,
|
||||
const QByteArray &newValue) {
|
||||
Q_UNUSED(characteristic);
|
||||
emit packetReceived();
|
||||
|
||||
qDebug() << QStringLiteral(" << ") << newValue.toHex(' ');
|
||||
}
|
||||
|
||||
void eliteariafan::fanSpeedRequest(uint8_t speed) {
|
||||
QSettings settings;
|
||||
if (speed > 100)
|
||||
speed = 100;
|
||||
double max = settings.value(QZSettings::fitmetria_fanfit_max, QZSettings::default_fitmetria_fanfit_max).toDouble();
|
||||
double min = settings.value(QZSettings::fitmetria_fanfit_min, QZSettings::default_fitmetria_fanfit_min).toDouble();
|
||||
|
||||
uint16_t speed8 = (uint8_t)((double)speed * (max - min) / 100.0 + min);
|
||||
|
||||
#ifdef Q_OS_IOS
|
||||
#ifndef IO_UNDER_QT
|
||||
iOS_EliteAriaFan->eliteAriaFan_fanSpeedRequest(speed8);
|
||||
#endif
|
||||
#else
|
||||
uint8_t init10[] = {0x03, 0x01, 0x0e};
|
||||
init10[2] = speed8;
|
||||
writeCharacteristic(gattWrite1Service, &gattWrite2Characteristic, init10, sizeof(init10),
|
||||
"forcing fan" + QString::number(speed));
|
||||
#endif
|
||||
}
|
||||
|
||||
void eliteariafan::writeCharacteristic(QLowEnergyService *service, QLowEnergyCharacteristic *writeChar,
|
||||
uint8_t *data, uint8_t data_len, const QString &info, bool disable_log,
|
||||
bool wait_for_response) {
|
||||
QEventLoop loop;
|
||||
QTimer timeout;
|
||||
|
||||
if (service == nullptr || writeChar->isValid() == false) {
|
||||
qDebug() << QStringLiteral(
|
||||
"eliteariafan trying to change the fan speed before the connection is estabilished");
|
||||
return;
|
||||
}
|
||||
|
||||
// if there are some crash here, maybe it's better to use 2 separate event for the characteristicChanged.
|
||||
// one for the resistance changed event (spontaneous), and one for the other ones.
|
||||
if (wait_for_response) {
|
||||
connect(service, &QLowEnergyService::characteristicChanged, &loop, &QEventLoop::quit);
|
||||
timeout.singleShot(300ms, &loop, &QEventLoop::quit);
|
||||
} else {
|
||||
connect(service, &QLowEnergyService::characteristicWritten, &loop, &QEventLoop::quit);
|
||||
timeout.singleShot(300ms, &loop, &QEventLoop::quit);
|
||||
}
|
||||
|
||||
if (service->state() != QLowEnergyService::ServiceState::ServiceDiscovered ||
|
||||
m_control->state() == QLowEnergyController::UnconnectedState) {
|
||||
qDebug() << QStringLiteral("writeCharacteristic error because the connection is closed");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!writeChar->isValid()) {
|
||||
qDebug() << QStringLiteral("gattWriteCharacteristic is invalid");
|
||||
return;
|
||||
}
|
||||
|
||||
if (writeBuffer) {
|
||||
delete writeBuffer;
|
||||
}
|
||||
writeBuffer = new QByteArray((const char *)data, data_len);
|
||||
|
||||
service->writeCharacteristic(*writeChar, *writeBuffer, QLowEnergyService::WriteWithoutResponse);
|
||||
|
||||
if (!disable_log) {
|
||||
qDebug() << QStringLiteral(" >> ") + writeBuffer->toHex(' ') + QStringLiteral(" // ") + info;
|
||||
}
|
||||
|
||||
loop.exec();
|
||||
}
|
||||
|
||||
void eliteariafan::stateChanged(QLowEnergyService::ServiceState state) {
|
||||
QBluetoothUuid _gattWriteCharacteristicId1(QStringLiteral("347b0012-7635-408b-8918-8ff3949ce592")); // handle 0x1d
|
||||
QBluetoothUuid _gattWriteCharacteristicId2(QStringLiteral("347b0040-7635-408b-8918-8ff3949ce592")); // handle 0x27
|
||||
|
||||
QMetaEnum metaEnum = QMetaEnum::fromType<QLowEnergyService::ServiceState>();
|
||||
emit debug(QStringLiteral("BTLE stateChanged ") + QString::fromLocal8Bit(metaEnum.valueToKey(state)));
|
||||
|
||||
for (QLowEnergyService *s : qAsConst(gattCommunicationChannelService)) {
|
||||
qDebug() << QStringLiteral("stateChanged") << s->serviceUuid() << s->state();
|
||||
if (s->state() != QLowEnergyService::ServiceDiscovered && s->state() != QLowEnergyService::InvalidService) {
|
||||
qDebug() << QStringLiteral("not all services discovered");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (state != QLowEnergyService::ServiceState::ServiceDiscovered) {
|
||||
qDebug() << QStringLiteral("ignoring this state");
|
||||
return;
|
||||
}
|
||||
|
||||
qDebug() << QStringLiteral("all services discovered!");
|
||||
|
||||
for (QLowEnergyService *s : qAsConst(gattCommunicationChannelService)) {
|
||||
if (s->state() == QLowEnergyService::ServiceDiscovered) {
|
||||
// establish hook into notifications
|
||||
connect(s, &QLowEnergyService::characteristicChanged, this, &eliteariafan::characteristicChanged);
|
||||
connect(s, &QLowEnergyService::characteristicWritten, this, &eliteariafan::characteristicWritten);
|
||||
connect(
|
||||
s, static_cast<void (QLowEnergyService::*)(QLowEnergyService::ServiceError)>(&QLowEnergyService::error),
|
||||
this, &eliteariafan::errorService);
|
||||
connect(s, &QLowEnergyService::descriptorWritten, this, &eliteariafan::descriptorWritten);
|
||||
|
||||
qDebug() << s->serviceUuid() << QStringLiteral("connected!");
|
||||
|
||||
auto characteristics_list = s->characteristics();
|
||||
for (const QLowEnergyCharacteristic &c : qAsConst(characteristics_list)) {
|
||||
qDebug() << QStringLiteral("char uuid") << c.uuid() << QStringLiteral("handle") << c.handle();
|
||||
auto descriptors_list = c.descriptors();
|
||||
for (const QLowEnergyDescriptor &d : qAsConst(descriptors_list)) {
|
||||
qDebug() << QStringLiteral("descriptor uuid") << d.uuid() << QStringLiteral("handle") << d.handle();
|
||||
}
|
||||
|
||||
if ((c.properties() & QLowEnergyCharacteristic::Notify) == QLowEnergyCharacteristic::Notify) {
|
||||
QByteArray descriptor;
|
||||
descriptor.append((char)0x01);
|
||||
descriptor.append((char)0x00);
|
||||
if (c.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration).isValid()) {
|
||||
s->writeDescriptor(c.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration), descriptor);
|
||||
} else {
|
||||
qDebug() << QStringLiteral("ClientCharacteristicConfiguration") << c.uuid()
|
||||
<< c.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration).uuid()
|
||||
<< c.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration).handle()
|
||||
<< QStringLiteral(" is not valid");
|
||||
}
|
||||
|
||||
qDebug() << s->serviceUuid() << c.uuid() << QStringLiteral("notification subscribed!");
|
||||
} else if ((c.properties() & QLowEnergyCharacteristic::Indicate) ==
|
||||
QLowEnergyCharacteristic::Indicate) {
|
||||
QByteArray descriptor;
|
||||
descriptor.append((char)0x02);
|
||||
descriptor.append((char)0x00);
|
||||
if (c.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration).isValid()) {
|
||||
s->writeDescriptor(c.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration), descriptor);
|
||||
} else {
|
||||
qDebug() << QStringLiteral("ClientCharacteristicConfiguration") << c.uuid()
|
||||
<< c.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration).uuid()
|
||||
<< c.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration).handle()
|
||||
<< QStringLiteral(" is not valid");
|
||||
}
|
||||
|
||||
qDebug() << s->serviceUuid() << c.uuid() << QStringLiteral("indication subscribed!");
|
||||
} else if ((c.properties() & QLowEnergyCharacteristic::Read) == QLowEnergyCharacteristic::Read) {
|
||||
// s->readCharacteristic(c);
|
||||
// qDebug() << s->serviceUuid() << c.uuid() << "reading!";
|
||||
}
|
||||
|
||||
if (c.uuid() == _gattWriteCharacteristicId1) {
|
||||
qDebug() << QStringLiteral("_gattWriteCharacteristicId1 found");
|
||||
gattWrite1Characteristic = c;
|
||||
gattWrite1Service = s;
|
||||
} else if (c.uuid() == _gattWriteCharacteristicId2) {
|
||||
qDebug() << QStringLiteral("_gattWriteCharacteristicId2 found");
|
||||
gattWrite2Characteristic = c;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void eliteariafan::descriptorWritten(const QLowEnergyDescriptor &descriptor, const QByteArray &newValue) {
|
||||
emit debug(QStringLiteral("descriptorWritten ") + descriptor.name() + " " + newValue.toHex(' '));
|
||||
initRequest = true;
|
||||
}
|
||||
|
||||
void eliteariafan::characteristicWritten(const QLowEnergyCharacteristic &characteristic,
|
||||
const QByteArray &newValue) {
|
||||
Q_UNUSED(characteristic);
|
||||
emit debug(QStringLiteral("characteristicWritten ") + newValue.toHex(' '));
|
||||
}
|
||||
|
||||
void eliteariafan::serviceScanDone(void) {
|
||||
emit debug(QStringLiteral("serviceScanDone"));
|
||||
|
||||
initRequest = false;
|
||||
|
||||
auto services_list = m_control->services();
|
||||
for (const QBluetoothUuid &s : qAsConst(services_list)) {
|
||||
gattCommunicationChannelService.append(m_control->createServiceObject(s));
|
||||
if (gattCommunicationChannelService.constLast()) {
|
||||
connect(gattCommunicationChannelService.constLast(), &QLowEnergyService::stateChanged, this,
|
||||
&eliteariafan::stateChanged);
|
||||
gattCommunicationChannelService.constLast()->discoverDetails();
|
||||
} else {
|
||||
m_control->disconnectFromDevice();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void eliteariafan::errorService(QLowEnergyService::ServiceError err) {
|
||||
QMetaEnum metaEnum = QMetaEnum::fromType<QLowEnergyService::ServiceError>();
|
||||
emit debug(QStringLiteral("eliteariafan::errorService") + QString::fromLocal8Bit(metaEnum.valueToKey(err)) +
|
||||
m_control->errorString());
|
||||
}
|
||||
|
||||
void eliteariafan::error(QLowEnergyController::Error err) {
|
||||
QMetaEnum metaEnum = QMetaEnum::fromType<QLowEnergyController::Error>();
|
||||
emit debug(QStringLiteral("eliteariafan::error") + QString::fromLocal8Bit(metaEnum.valueToKey(err)) +
|
||||
m_control->errorString());
|
||||
}
|
||||
|
||||
void eliteariafan::deviceDiscovered(const QBluetoothDeviceInfo &device) {
|
||||
QSettings settings;
|
||||
emit debug(QStringLiteral("Found new device: ") + device.name() + QStringLiteral(" (") +
|
||||
device.address().toString() + ')');
|
||||
|
||||
#ifdef Q_OS_IOS
|
||||
#ifndef IO_UNDER_QT
|
||||
iOS_EliteAriaFan = new lockscreen();
|
||||
iOS_EliteAriaFan->eliteAriaFan();
|
||||
return;
|
||||
#endif
|
||||
#endif
|
||||
{
|
||||
bluetoothDevice = device;
|
||||
m_control = QLowEnergyController::createCentral(bluetoothDevice, this);
|
||||
connect(m_control, &QLowEnergyController::serviceDiscovered, this, &eliteariafan::serviceDiscovered);
|
||||
connect(m_control, &QLowEnergyController::discoveryFinished, this, &eliteariafan::serviceScanDone);
|
||||
connect(m_control,
|
||||
static_cast<void (QLowEnergyController::*)(QLowEnergyController::Error)>(&QLowEnergyController::error),
|
||||
this, &eliteariafan::error);
|
||||
connect(m_control, &QLowEnergyController::stateChanged, this, &eliteariafan::controllerStateChanged);
|
||||
|
||||
connect(m_control,
|
||||
static_cast<void (QLowEnergyController::*)(QLowEnergyController::Error)>(&QLowEnergyController::error),
|
||||
this, [this](QLowEnergyController::Error error) {
|
||||
Q_UNUSED(error);
|
||||
Q_UNUSED(this);
|
||||
emit debug(QStringLiteral("Cannot connect to remote device."));
|
||||
emit disconnected();
|
||||
});
|
||||
connect(m_control, &QLowEnergyController::connected, this, [this]() {
|
||||
Q_UNUSED(this);
|
||||
emit debug(QStringLiteral("Controller connected. Search services..."));
|
||||
m_control->discoverServices();
|
||||
});
|
||||
connect(m_control, &QLowEnergyController::disconnected, this, [this]() {
|
||||
Q_UNUSED(this);
|
||||
emit debug(QStringLiteral("LowEnergy controller disconnected"));
|
||||
emit disconnected();
|
||||
});
|
||||
|
||||
// Connect
|
||||
m_control->connectToDevice();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bool eliteariafan::connected() {
|
||||
#ifdef Q_OS_IOS
|
||||
return true;
|
||||
#endif
|
||||
|
||||
if (!m_control) {
|
||||
return false;
|
||||
}
|
||||
return m_control->state() == QLowEnergyController::DiscoveredState;
|
||||
}
|
||||
|
||||
void eliteariafan::controllerStateChanged(QLowEnergyController::ControllerState state) {
|
||||
#ifdef Q_OS_IOS
|
||||
return;
|
||||
#endif
|
||||
|
||||
qDebug() << QStringLiteral("controllerStateChanged") << state;
|
||||
if (state == QLowEnergyController::UnconnectedState && m_control) {
|
||||
qDebug() << QStringLiteral("trying to connect back again...");
|
||||
initRequest = false;
|
||||
initDone = false;
|
||||
|
||||
m_control->connectToDevice();
|
||||
}
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
#ifndef ELITEARIAFAN_H
|
||||
#define ELITEARIAFAN_H
|
||||
|
||||
#include <QBluetoothDeviceDiscoveryAgent>
|
||||
#include <QtBluetooth/qlowenergyadvertisingdata.h>
|
||||
#include <QtBluetooth/qlowenergyadvertisingparameters.h>
|
||||
#include <QtBluetooth/qlowenergycharacteristic.h>
|
||||
#include <QtBluetooth/qlowenergycharacteristicdata.h>
|
||||
#include <QtBluetooth/qlowenergycontroller.h>
|
||||
#include <QtBluetooth/qlowenergydescriptordata.h>
|
||||
#include <QtBluetooth/qlowenergyservice.h>
|
||||
#include <QtBluetooth/qlowenergyservicedata.h>
|
||||
#include <QtCore/qbytearray.h>
|
||||
|
||||
#ifndef Q_OS_ANDROID
|
||||
#include <QtCore/qcoreapplication.h>
|
||||
#else
|
||||
#include <QtGui/qguiapplication.h>
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_IOS
|
||||
#include "ios/lockscreen.h"
|
||||
#endif
|
||||
|
||||
#include <QtCore/qlist.h>
|
||||
#include <QtCore/qmutex.h>
|
||||
#include <QtCore/qscopedpointer.h>
|
||||
#include <QtCore/qtimer.h>
|
||||
|
||||
#include <QObject>
|
||||
#include <QTime>
|
||||
|
||||
#include "bluetoothdevice.h"
|
||||
|
||||
class eliteariafan : public bluetoothdevice {
|
||||
Q_OBJECT
|
||||
public:
|
||||
eliteariafan(bluetoothdevice *parentDevice);
|
||||
bool connected() override;
|
||||
|
||||
private:
|
||||
QList<QLowEnergyService *> gattCommunicationChannelService;
|
||||
QLowEnergyCharacteristic gattNotify1Characteristic;
|
||||
QLowEnergyCharacteristic gattNotify2Characteristic;
|
||||
QLowEnergyCharacteristic gattWrite1Characteristic;
|
||||
QLowEnergyService *gattWrite1Service;
|
||||
QLowEnergyCharacteristic gattWrite2Characteristic;
|
||||
|
||||
void writeCharacteristic(QLowEnergyService *service, QLowEnergyCharacteristic *writeChar, uint8_t *data,
|
||||
uint8_t data_len, const QString &info, bool disable_log = false,
|
||||
bool wait_for_response = false);
|
||||
|
||||
bluetoothdevice *parentDevice = nullptr;
|
||||
|
||||
bool initDone = false;
|
||||
bool initRequest = false;
|
||||
|
||||
QTimer *refresh;
|
||||
|
||||
#ifdef Q_OS_IOS
|
||||
lockscreen* iOS_EliteAriaFan = nullptr;
|
||||
#endif
|
||||
|
||||
|
||||
signals:
|
||||
void disconnected();
|
||||
void debug(QString string);
|
||||
void packetReceived();
|
||||
|
||||
public slots:
|
||||
void deviceDiscovered(const QBluetoothDeviceInfo &device);
|
||||
void disconnectBluetooth();
|
||||
void fanSpeedRequest(uint8_t value);
|
||||
|
||||
private slots:
|
||||
|
||||
void characteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &newValue);
|
||||
void characteristicWritten(const QLowEnergyCharacteristic &characteristic, const QByteArray &newValue);
|
||||
void descriptorWritten(const QLowEnergyDescriptor &descriptor, const QByteArray &newValue);
|
||||
void stateChanged(QLowEnergyService::ServiceState state);
|
||||
void controllerStateChanged(QLowEnergyController::ControllerState state);
|
||||
|
||||
void serviceDiscovered(const QBluetoothUuid &gatt);
|
||||
void serviceScanDone(void);
|
||||
void update();
|
||||
void error(QLowEnergyController::Error err);
|
||||
void errorService(QLowEnergyService::ServiceError);
|
||||
};
|
||||
|
||||
#endif // ELITEARIAFAN_H
|
||||
@@ -67,7 +67,6 @@ double elliptical::speedFromWatts() {
|
||||
if (wattsMetric().value() > 0) {
|
||||
double vwatts = ((9.8 * weight) * (currentInclination().value() / 100.0));
|
||||
speed = 210.0 / ((wattsMetric().value() - vwatts) / 75.0 / weight * 1000.0);
|
||||
speed = 60.0 / speed;
|
||||
}
|
||||
return speed;
|
||||
}
|
||||
@@ -108,7 +107,6 @@ void elliptical::clearStats() {
|
||||
Speed.clear(false);
|
||||
KCal.clear(true);
|
||||
Distance.clear(true);
|
||||
Distance1s.clear(true);
|
||||
Heart.clear(false);
|
||||
m_jouls.clear(true);
|
||||
elevationAcc = 0;
|
||||
@@ -125,7 +123,6 @@ void elliptical::setPaused(bool p) {
|
||||
Speed.setPaused(p);
|
||||
KCal.setPaused(p);
|
||||
Distance.setPaused(p);
|
||||
Distance1s.setPaused(p);
|
||||
Heart.setPaused(p);
|
||||
m_jouls.setPaused(p);
|
||||
m_watt.setPaused(p);
|
||||
@@ -140,7 +137,6 @@ void elliptical::setLap() {
|
||||
Speed.setLap(false);
|
||||
KCal.setLap(true);
|
||||
Distance.setLap(true);
|
||||
Distance1s.setLap(true);
|
||||
Heart.setLap(false);
|
||||
m_jouls.setLap(true);
|
||||
m_watt.setLap(false);
|
||||
|
||||
@@ -27,7 +27,7 @@ class elliptical : public bluetoothdevice {
|
||||
void clearStats() override;
|
||||
void setPaused(bool p) override;
|
||||
void setLap() override;
|
||||
virtual uint16_t watts();
|
||||
uint16_t watts();
|
||||
double speedFromWatts();
|
||||
void setGears(double d);
|
||||
double gears();
|
||||
|
||||
@@ -390,10 +390,7 @@ void eslinkertreadmill::characteristicChanged(const QLowEnergyCharacteristic &ch
|
||||
}
|
||||
} else if (treadmill_type == COSTAWAY) {
|
||||
const double miles = 1.60934;
|
||||
if(newValue.at(3) == 0xFF)
|
||||
Speed = 0;
|
||||
else
|
||||
Speed = (double)((uint8_t)newValue.at(3)) / 10.0 * miles;
|
||||
Speed = newValue.at(3) * miles;
|
||||
Inclination = 0; // this treadmill doesn't have inclination
|
||||
emit debug(QStringLiteral("Current speed: ") + QString::number(Speed.value()));
|
||||
}
|
||||
|
||||
@@ -32,7 +32,6 @@ void faketreadmill::update() {
|
||||
QSettings settings;
|
||||
QString heartRateBeltName =
|
||||
settings.value(QZSettings::heart_rate_belt_name, QZSettings::default_heart_rate_belt_name).toString();
|
||||
QDateTime now = QDateTime::currentDateTime();
|
||||
|
||||
update_metrics(true, watts(settings.value(QZSettings::weight, QZSettings::default_weight).toFloat()));
|
||||
|
||||
@@ -51,8 +50,8 @@ void faketreadmill::update() {
|
||||
cadenceFromAppleWatch();
|
||||
|
||||
Distance += ((Speed.value() / (double)3600.0) /
|
||||
((double)1000.0 / (double)(lastRefreshCharacteristicChanged.msecsTo(now))));
|
||||
lastRefreshCharacteristicChanged = now;
|
||||
((double)1000.0 / (double)(lastRefreshCharacteristicChanged.msecsTo(QDateTime::currentDateTime()))));
|
||||
lastRefreshCharacteristicChanged = QDateTime::currentDateTime();
|
||||
|
||||
// ******************************************* virtual treadmill init *************************************
|
||||
if (!firstStateChanged && !this->hasVirtualDevice()) {
|
||||
|
||||
@@ -376,7 +376,6 @@ void fitplusbike::serviceDiscovered(const QBluetoothUuid &gatt) {
|
||||
}
|
||||
|
||||
void fitplusbike::characteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &newValue) {
|
||||
QDateTime now = QDateTime::currentDateTime();
|
||||
// qDebug() << "characteristicChanged" << characteristic.uuid() << newValue << newValue.length();
|
||||
Q_UNUSED(characteristic);
|
||||
QSettings settings;
|
||||
@@ -429,7 +428,7 @@ void fitplusbike::characteristicChanged(const QLowEnergyCharacteristic &characte
|
||||
} else {
|
||||
Speed = metric::calculateSpeedFromPower(
|
||||
watts(), Inclination.value(), Speed.value(),
|
||||
fabs(now.msecsTo(Speed.lastChanged()) / 1000.0), this->speedLimit());
|
||||
fabs(QDateTime::currentDateTime().msecsTo(Speed.lastChanged()) / 1000.0), this->speedLimit());
|
||||
}
|
||||
index += 2;
|
||||
qDebug() << QStringLiteral("Current Speed: ") + QString::number(Speed.value());
|
||||
@@ -526,7 +525,7 @@ void fitplusbike::characteristicChanged(const QLowEnergyCharacteristic &characte
|
||||
200.0) /
|
||||
(60000.0 /
|
||||
((double)lastRefreshCharacteristicChanged.msecsTo(
|
||||
now)))); //(( (0.048* Output in watts +1.19) * body weight in
|
||||
QDateTime::currentDateTime())))); //(( (0.048* Output in watts +1.19) * body weight in
|
||||
// kg * 3.5) / 200 ) / 60
|
||||
}
|
||||
|
||||
@@ -539,7 +538,7 @@ void fitplusbike::characteristicChanged(const QLowEnergyCharacteristic &characte
|
||||
#endif
|
||||
{
|
||||
if (Flags.heartRate && !disable_hr_frommachinery && newValue.length() > index) {
|
||||
Heart = ((double)(((uint8_t)newValue.at(index))));
|
||||
Heart = ((double)((newValue.at(index))));
|
||||
// index += 1; // NOTE: clang-analyzer-deadcode.DeadStores
|
||||
qDebug() << (QStringLiteral("Current Heart: ") + QString::number(Heart.value()));
|
||||
} else {
|
||||
@@ -598,7 +597,7 @@ void fitplusbike::characteristicChanged(const QLowEnergyCharacteristic &characte
|
||||
else*/
|
||||
Speed = metric::calculateSpeedFromPower(
|
||||
watts(), Inclination.value(), Speed.value(),
|
||||
fabs(now.msecsTo(Speed.lastChanged()) / 1000.0), this->speedLimit());
|
||||
fabs(QDateTime::currentDateTime().msecsTo(Speed.lastChanged()) / 1000.0), this->speedLimit());
|
||||
|
||||
} else if (newValue.length() == 13) {
|
||||
|
||||
@@ -626,7 +625,7 @@ void fitplusbike::characteristicChanged(const QLowEnergyCharacteristic &characte
|
||||
else
|
||||
Speed = metric::calculateSpeedFromPower(
|
||||
watts(), Inclination.value(), Speed.value(),
|
||||
fabs(now.msecsTo(Speed.lastChanged()) / 1000.0), this->speedLimit());
|
||||
fabs(QDateTime::currentDateTime().msecsTo(Speed.lastChanged()) / 1000.0), this->speedLimit());
|
||||
}
|
||||
|
||||
if (watts())
|
||||
@@ -635,17 +634,17 @@ void fitplusbike::characteristicChanged(const QLowEnergyCharacteristic &characte
|
||||
settings.value(QZSettings::weight, QZSettings::default_weight).toFloat() * 3.5) /
|
||||
200.0) /
|
||||
(60000.0 / ((double)lastRefreshCharacteristicChanged.msecsTo(
|
||||
now)))); //(( (0.048* Output in watts +1.19) * body weight in kg
|
||||
QDateTime::currentDateTime())))); //(( (0.048* Output in watts +1.19) * body weight in kg
|
||||
//* 3.5) / 200 ) / 60
|
||||
Distance += ((Speed.value() / 3600000.0) *
|
||||
((double)lastRefreshCharacteristicChanged.msecsTo(now)));
|
||||
((double)lastRefreshCharacteristicChanged.msecsTo(QDateTime::currentDateTime())));
|
||||
|
||||
if (Cadence.value() > 0) {
|
||||
CrankRevs++;
|
||||
LastCrankEventTime += (uint16_t)(1024.0 / (((double)(Cadence.value())) / 60.0));
|
||||
}
|
||||
|
||||
lastRefreshCharacteristicChanged = now;
|
||||
lastRefreshCharacteristicChanged = QDateTime::currentDateTime();
|
||||
|
||||
#ifdef Q_OS_ANDROID
|
||||
if (settings.value(QZSettings::ant_heart, QZSettings::default_ant_heart).toBool())
|
||||
@@ -919,7 +918,6 @@ void fitplusbike::deviceDiscovered(const QBluetoothDeviceInfo &device) {
|
||||
bluetoothDevice = device;
|
||||
|
||||
if (device.name().startsWith(QStringLiteral("MRK-"))) {
|
||||
qDebug() << QStringLiteral("merach_MRK workaround enabled!");
|
||||
merach_MRK = true;
|
||||
}
|
||||
|
||||
@@ -989,91 +987,50 @@ uint16_t fitplusbike::wattsFromResistance(double resistance) {
|
||||
(double)(currentCadence().value()))) * exp(0.088 * (double)(currentResistance().value())) );*/
|
||||
|
||||
const double Epsilon = 4.94065645841247E-324;
|
||||
const int wattTableFirstDimension = 25;
|
||||
const int wattTableSecondDimension = 11;
|
||||
double wattTable[wattTableFirstDimension][wattTableSecondDimension] = {
|
||||
{Epsilon, 15.0, 15.0, 15.0, 20.0, 30.0, 32.0, 38.0, 44.0, 56.0, 66.0},
|
||||
{Epsilon, 15.0, 15.0, 15.0, 20.0, 30.0, 32.0, 38.0, 44.0, 56.0, 66.0},
|
||||
{Epsilon, 16.0, 16.0, 16.0, 22.0, 30.0, 38.0, 45.0, 53.0, 67.0, 79.0},
|
||||
{Epsilon, 18.0, 18.0, 18.0, 26.0, 34.0, 43.0, 52.0, 62.0, 78.0, 92.0},
|
||||
{Epsilon, 20.0, 20.0, 20.0, 28.0, 38.0, 48.0, 59.0, 71.0, 89.0, 105.0},
|
||||
{Epsilon, 23.0, 23.0, 23.0, 32.0, 43.0, 54.0, 66.0, 80.0, 100.0, 118.0},
|
||||
{Epsilon, 24.0, 24.0, 24.0, 35.0, 46.0, 59.0, 73.0, 89.0, 110.0, 130.0},
|
||||
{Epsilon, 26.0, 26.0, 26.0, 37.0, 51.0, 65.0, 81.0, 98.0, 122.0, 143.0},
|
||||
{Epsilon, 28.0, 28.0, 28.0, 41.0, 56.0, 71.0, 88.0, 107.0, 133.0, 156.0},
|
||||
{Epsilon, 30.0, 30.0, 30.0, 44.0, 60.0, 77.0, 96.0, 116.0, 144.0, 169.0},
|
||||
{Epsilon, 33.0, 33.0, 33.0, 47.0, 65.0, 83.0, 103.0, 125.0, 155.0, 182.0},
|
||||
{Epsilon, 34.0, 34.0, 34.0, 50.0, 70.0, 89.0, 110.0, 134.0, 166.0, 195.0},
|
||||
{Epsilon, 37.0, 37.0, 37.0, 54.0, 74.0, 94.0, 117.0, 143.0, 177.0, 208.0},
|
||||
{Epsilon, 38.0, 38.0, 38.0, 56.0, 78.0, 100.0, 125.0, 152.0, 188.0, 220.0},
|
||||
{Epsilon, 41.0, 41.0, 41.0, 60.0, 82.0, 106.0, 132.0, 161.0, 199.0, 233.0},
|
||||
{Epsilon, 43.0, 43.0, 43.0, 62.0, 86.0, 111.0, 139.0, 170.0, 209.0, 245.0},
|
||||
{Epsilon, 45.0, 45.0, 45.0, 66.0, 91.0, 117.0, 147.0, 180.0, 220.0, 259.0},
|
||||
{Epsilon, 48.0, 48.0, 48.0, 70.0, 96.0, 124.0, 155.0, 190.0, 232.0, 273.0},
|
||||
{Epsilon, 50.0, 50.0, 50.0, 73.0, 101.0, 130.0, 163.0, 200.0, 244.0, 287.0},
|
||||
{Epsilon, 52.0, 52.0, 52.0, 76.0, 106.0, 136.0, 171.0, 210.0, 256.0, 300.0},
|
||||
{Epsilon, 54.0, 54.0, 54.0, 80.0, 111.0, 143.0, 179.0, 220.0, 268.0, 314.0},
|
||||
{Epsilon, 57.0, 57.0, 57.0, 84.0, 116.0, 149.0, 187.0, 230.0, 279.0, 327.0},
|
||||
{Epsilon, 59.0, 59.0, 59.0, 87.0, 121.0, 155.0, 195.0, 240.0, 290.0, 340.0},
|
||||
{Epsilon, 62.0, 62.0, 62.0, 91.0, 126.0, 162.0, 203.0, 250.0, 302.0, 353.0},
|
||||
{Epsilon, 64.0, 64.0, 64.0, 94.0, 130.0, 168.0, 211.0, 260.0, 313.0, 366.0}};
|
||||
|
||||
if (merach_MRK) {
|
||||
const int wattTableFirstDimension = 17;
|
||||
const int wattTableSecondDimension = 11;
|
||||
double wattTable[wattTableFirstDimension][wattTableSecondDimension] = {
|
||||
{Epsilon, 14.3, 28.6, 42.9, 57.2, 71.5, 85.8, 100.1, 114.4, 128.7, 143.0},
|
||||
{Epsilon, 14.3, 28.6, 42.9, 57.2, 71.5, 85.8, 100.1, 114.4, 128.7, 143.0},
|
||||
{Epsilon, 16.4, 32.8, 49.2, 65.6, 82.0, 98.4, 114.8, 131.2, 147.6, 164.0},
|
||||
{Epsilon, 18.7, 37.4, 56.1, 74.8, 93.5, 112.2, 130.9, 149.6, 168.3, 187.0},
|
||||
{Epsilon, 21.0, 42.0, 63.0, 84.0, 105.0, 126.0, 147.0, 168.0, 189.0, 210.0},
|
||||
{Epsilon, 23.2, 46.4, 69.6, 92.8, 116.0, 139.2, 162.4, 185.6, 208.8, 232.0},
|
||||
{Epsilon, 25.3, 50.6, 75.9, 101.2, 126.5, 151.8, 177.1, 202.4, 227.7, 253.0},
|
||||
{Epsilon, 27.6, 55.2, 82.8, 110.4, 138.0, 165.6, 193.2, 220.8, 248.4, 276.0},
|
||||
{Epsilon, 30.0, 60.0, 90.0, 120.0, 150.0, 180.0, 210.0, 240.0, 270.0, 300.0},
|
||||
{Epsilon, 31.9, 63.8, 95.7, 127.6, 159.5, 191.4, 223.3, 255.2, 287.1, 319.0},
|
||||
{Epsilon, 34.2, 68.4, 102.6, 136.8, 171.0, 205.2, 239.4, 273.6, 307.8, 342.0},
|
||||
{Epsilon, 36.5, 73.0, 109.5, 146.0, 182.5, 219.0, 255.5, 292.0, 328.5, 365.0},
|
||||
{Epsilon, 38.5, 77.0, 115.5, 154.0, 192.5, 231.0, 269.5, 308.0, 346.5, 385.0},
|
||||
{Epsilon, 40.8, 81.6, 122.4, 163.2, 204.0, 244.8, 285.6, 326.4, 367.2, 408.0},
|
||||
{Epsilon, 43.1, 86.2, 129.3, 172.4, 215.5, 258.6, 301.7, 344.8, 387.9, 431.0},
|
||||
{Epsilon, 45.1, 90.2, 135.3, 180.4, 225.5, 270.6, 315.7, 360.8, 405.9, 451.0},
|
||||
{Epsilon, 47.2, 94.4, 141.6, 188.8, 236.0, 283.2, 330.4, 377.6, 424.8, 472.0}};
|
||||
|
||||
int level = resistance;
|
||||
if (level < 0) {
|
||||
level = 0;
|
||||
}
|
||||
if (level >= wattTableFirstDimension) {
|
||||
level = wattTableFirstDimension - 1;
|
||||
}
|
||||
double *watts_of_level = wattTable[level];
|
||||
int watt_setp = (Cadence.value() / 10.0);
|
||||
if (watt_setp >= 10) {
|
||||
return (((double)Cadence.value()) / 100.0) * watts_of_level[wattTableSecondDimension - 1];
|
||||
}
|
||||
double watt_base = watts_of_level[watt_setp];
|
||||
return (((watts_of_level[watt_setp + 1] - watt_base) / 10.0) * ((double)(((int)(Cadence.value())) % 10))) +
|
||||
watt_base;
|
||||
} else {
|
||||
// VirtuFit Etappe 2.0i Spinbike ERG Table #1526
|
||||
const int wattTableFirstDimension = 25;
|
||||
const int wattTableSecondDimension = 11;
|
||||
double wattTable[wattTableFirstDimension][wattTableSecondDimension] = {
|
||||
{Epsilon, 15.0, 15.0, 15.0, 20.0, 30.0, 32.0, 38.0, 44.0, 56.0, 66.0},
|
||||
{Epsilon, 15.0, 15.0, 15.0, 20.0, 30.0, 32.0, 38.0, 44.0, 56.0, 66.0},
|
||||
{Epsilon, 16.0, 16.0, 16.0, 22.0, 30.0, 38.0, 45.0, 53.0, 67.0, 79.0},
|
||||
{Epsilon, 18.0, 18.0, 18.0, 26.0, 34.0, 43.0, 52.0, 62.0, 78.0, 92.0},
|
||||
{Epsilon, 20.0, 20.0, 20.0, 28.0, 38.0, 48.0, 59.0, 71.0, 89.0, 105.0},
|
||||
{Epsilon, 23.0, 23.0, 23.0, 32.0, 43.0, 54.0, 66.0, 80.0, 100.0, 118.0},
|
||||
{Epsilon, 24.0, 24.0, 24.0, 35.0, 46.0, 59.0, 73.0, 89.0, 110.0, 130.0},
|
||||
{Epsilon, 26.0, 26.0, 26.0, 37.0, 51.0, 65.0, 81.0, 98.0, 122.0, 143.0},
|
||||
{Epsilon, 28.0, 28.0, 28.0, 41.0, 56.0, 71.0, 88.0, 107.0, 133.0, 156.0},
|
||||
{Epsilon, 30.0, 30.0, 30.0, 44.0, 60.0, 77.0, 96.0, 116.0, 144.0, 169.0},
|
||||
{Epsilon, 33.0, 33.0, 33.0, 47.0, 65.0, 83.0, 103.0, 125.0, 155.0, 182.0},
|
||||
{Epsilon, 34.0, 34.0, 34.0, 50.0, 70.0, 89.0, 110.0, 134.0, 166.0, 195.0},
|
||||
{Epsilon, 37.0, 37.0, 37.0, 54.0, 74.0, 94.0, 117.0, 143.0, 177.0, 208.0},
|
||||
{Epsilon, 38.0, 38.0, 38.0, 56.0, 78.0, 100.0, 125.0, 152.0, 188.0, 220.0},
|
||||
{Epsilon, 41.0, 41.0, 41.0, 60.0, 82.0, 106.0, 132.0, 161.0, 199.0, 233.0},
|
||||
{Epsilon, 43.0, 43.0, 43.0, 62.0, 86.0, 111.0, 139.0, 170.0, 209.0, 245.0},
|
||||
{Epsilon, 45.0, 45.0, 45.0, 66.0, 91.0, 117.0, 147.0, 180.0, 220.0, 259.0},
|
||||
{Epsilon, 48.0, 48.0, 48.0, 70.0, 96.0, 124.0, 155.0, 190.0, 232.0, 273.0},
|
||||
{Epsilon, 50.0, 50.0, 50.0, 73.0, 101.0, 130.0, 163.0, 200.0, 244.0, 287.0},
|
||||
{Epsilon, 52.0, 52.0, 52.0, 76.0, 106.0, 136.0, 171.0, 210.0, 256.0, 300.0},
|
||||
{Epsilon, 54.0, 54.0, 54.0, 80.0, 111.0, 143.0, 179.0, 220.0, 268.0, 314.0},
|
||||
{Epsilon, 57.0, 57.0, 57.0, 84.0, 116.0, 149.0, 187.0, 230.0, 279.0, 327.0},
|
||||
{Epsilon, 59.0, 59.0, 59.0, 87.0, 121.0, 155.0, 195.0, 240.0, 290.0, 340.0},
|
||||
{Epsilon, 62.0, 62.0, 62.0, 91.0, 126.0, 162.0, 203.0, 250.0, 302.0, 353.0},
|
||||
{Epsilon, 64.0, 64.0, 64.0, 94.0, 130.0, 168.0, 211.0, 260.0, 313.0, 366.0}};
|
||||
|
||||
int level = resistance;
|
||||
if (level < 0) {
|
||||
level = 0;
|
||||
}
|
||||
if (level >= wattTableFirstDimension) {
|
||||
level = wattTableFirstDimension - 1;
|
||||
}
|
||||
double *watts_of_level = wattTable[level];
|
||||
int watt_setp = (Cadence.value() / 10.0);
|
||||
if (watt_setp >= 10) {
|
||||
return (((double)Cadence.value()) / 100.0) * watts_of_level[wattTableSecondDimension - 1];
|
||||
}
|
||||
double watt_base = watts_of_level[watt_setp];
|
||||
return (((watts_of_level[watt_setp + 1] - watt_base) / 10.0) * ((double)(((int)(Cadence.value())) % 10))) +
|
||||
watt_base;
|
||||
int level = resistance;
|
||||
if (level < 0) {
|
||||
level = 0;
|
||||
}
|
||||
if (level >= wattTableFirstDimension) {
|
||||
level = wattTableFirstDimension - 1;
|
||||
}
|
||||
double *watts_of_level = wattTable[level];
|
||||
int watt_setp = (Cadence.value() / 10.0);
|
||||
if (watt_setp >= 10) {
|
||||
return (((double)Cadence.value()) / 100.0) * watts_of_level[wattTableSecondDimension - 1];
|
||||
}
|
||||
double watt_base = watts_of_level[watt_setp];
|
||||
return (((watts_of_level[watt_setp + 1] - watt_base) / 10.0) * ((double)(((int)(Cadence.value())) % 10))) +
|
||||
watt_base;
|
||||
}
|
||||
|
||||
resistance_t fitplusbike::resistanceFromPowerRequest(uint16_t power) {
|
||||
|
||||
@@ -276,8 +276,7 @@ void fitshowtreadmill::serviceDiscovered(const QBluetoothUuid &gatt) {
|
||||
QBluetoothUuid nobleproconnect(QStringLiteral("0000ae00-0000-1000-8000-00805f9b34fb"));
|
||||
emit debug(QStringLiteral("serviceDiscovered ") + gatt.toString() + QStringLiteral(" ") +
|
||||
QString::number(servRepr));
|
||||
if ((gatt == nobleproconnect && serviceId.isNull()) || servRepr == 0xfff0 || (servRepr == 0xffe0 && serviceId.isNull())) {
|
||||
qDebug() << "adding" << gatt.toString() << "as the default service";
|
||||
if (gatt == nobleproconnect || servRepr == 0xfff0 || (servRepr == 0xffe0 && serviceId.isNull())) {
|
||||
serviceId = gatt; // NOTE: clazy-rule-of-tow
|
||||
}
|
||||
}
|
||||
@@ -471,11 +470,7 @@ void fitshowtreadmill::characteristicChanged(const QLowEnergyCharacteristic &cha
|
||||
.toBool())
|
||||
miles = 1.60934;
|
||||
|
||||
if(IS_RUNNING)
|
||||
Speed = speed * miles;
|
||||
else
|
||||
Speed = 0;
|
||||
|
||||
Speed = speed * miles;
|
||||
if (Speed.value() != speed) {
|
||||
emit speedChanged(speed);
|
||||
}
|
||||
@@ -504,9 +499,6 @@ void fitshowtreadmill::characteristicChanged(const QLowEnergyCharacteristic &cha
|
||||
long appleWatchHeartRate = h->heartRate();
|
||||
h->setKcal(KCal.value());
|
||||
h->setDistance(Distance.value());
|
||||
h->setSpeed(Speed.value());
|
||||
h->setPower(m_watt.value());
|
||||
h->setCadence(Cadence.value());
|
||||
Heart = appleWatchHeartRate;
|
||||
debug("Current Heart from Apple Watch: " + QString::number(appleWatchHeartRate));
|
||||
#else
|
||||
|
||||
@@ -240,7 +240,6 @@ void flywheelbike::updateStats() {
|
||||
}
|
||||
|
||||
void flywheelbike::characteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &newValue) {
|
||||
QDateTime now = QDateTime::currentDateTime();
|
||||
static uint8_t zero_fix_filter = 0;
|
||||
// qDebug() << "characteristicChanged" << characteristic.uuid() << newValue << newValue.length();
|
||||
Q_UNUSED(characteristic);
|
||||
@@ -294,7 +293,7 @@ void flywheelbike::characteristicChanged(const QLowEnergyCharacteristic &charact
|
||||
} else {
|
||||
Speed = metric::calculateSpeedFromPower(
|
||||
watts(), Inclination.value(), Speed.value(),
|
||||
fabs(now.msecsTo(Speed.lastChanged()) / 1000.0), this->speedLimit());
|
||||
fabs(QDateTime::currentDateTime().msecsTo(Speed.lastChanged()) / 1000.0), this->speedLimit());
|
||||
}
|
||||
|
||||
// https://www.facebook.com/groups/149984563348738/permalink/174268944253633/?comment_id=174366620910532&reply_comment_id=174666314213896
|
||||
|
||||
@@ -39,12 +39,6 @@ void ftmsbike::writeCharacteristic(uint8_t *data, uint8_t data_len, const QStrin
|
||||
bool wait_for_response) {
|
||||
QEventLoop loop;
|
||||
QTimer timeout;
|
||||
|
||||
if(!gattFTMSService) {
|
||||
qDebug() << QStringLiteral("gattFTMSService is null!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (wait_for_response) {
|
||||
connect(gattFTMSService, &QLowEnergyService::characteristicChanged, &loop, &QEventLoop::quit);
|
||||
timeout.singleShot(300ms, &loop, &QEventLoop::quit);
|
||||
@@ -58,15 +52,11 @@ void ftmsbike::writeCharacteristic(uint8_t *data, uint8_t data_len, const QStrin
|
||||
}
|
||||
writeBuffer = new QByteArray((const char *)data, data_len);
|
||||
|
||||
if (gattWriteCharControlPointId.properties() & QLowEnergyCharacteristic::WriteNoResponse) {
|
||||
gattFTMSService->writeCharacteristic(gattWriteCharControlPointId, *writeBuffer,
|
||||
QLowEnergyService::WriteWithoutResponse);
|
||||
} else {
|
||||
gattFTMSService->writeCharacteristic(gattWriteCharControlPointId, *writeBuffer);
|
||||
}
|
||||
gattFTMSService->writeCharacteristic(gattWriteCharControlPointId, *writeBuffer);
|
||||
|
||||
if (!disable_log) {
|
||||
emit debug(QStringLiteral(" >> ") + writeBuffer->toHex(' ') + QStringLiteral(" // ") + info);
|
||||
emit debug(QStringLiteral(" >> ") + writeBuffer->toHex(' ') +
|
||||
QStringLiteral(" // ") + info);
|
||||
}
|
||||
|
||||
loop.exec();
|
||||
@@ -99,8 +89,7 @@ void ftmsbike::forcePower(int16_t requestPower) {
|
||||
void ftmsbike::forceResistance(resistance_t requestResistance) {
|
||||
|
||||
QSettings settings;
|
||||
if (!settings.value(QZSettings::ss2k_peloton, QZSettings::default_ss2k_peloton).toBool() &&
|
||||
resistance_lvl_mode == false) {
|
||||
if (!settings.value(QZSettings::ss2k_peloton, QZSettings::default_ss2k_peloton).toBool()) {
|
||||
uint8_t write[] = {FTMS_SET_INDOOR_BIKE_SIMULATION_PARAMS, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
|
||||
double fr = (((double)requestResistance) * bikeResistanceGain) + ((double)bikeResistanceOffset);
|
||||
@@ -197,7 +186,6 @@ void ftmsbike::serviceDiscovered(const QBluetoothUuid &gatt) {
|
||||
}
|
||||
|
||||
void ftmsbike::characteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &newValue) {
|
||||
QDateTime now = QDateTime::currentDateTime();
|
||||
// qDebug() << "characteristicChanged" << characteristic.uuid() << newValue << newValue.length();
|
||||
Q_UNUSED(characteristic);
|
||||
QSettings settings;
|
||||
@@ -247,7 +235,7 @@ void ftmsbike::characteristicChanged(const QLowEnergyCharacteristic &characteris
|
||||
} else {
|
||||
Speed = metric::calculateSpeedFromPower(
|
||||
watts(), Inclination.value(), Speed.value(),
|
||||
fabs(now.msecsTo(Speed.lastChanged()) / 1000.0), this->speedLimit());
|
||||
fabs(QDateTime::currentDateTime().msecsTo(Speed.lastChanged()) / 1000.0), this->speedLimit());
|
||||
}
|
||||
index += 2;
|
||||
emit debug(QStringLiteral("Current Speed: ") + QString::number(Speed.value()));
|
||||
@@ -284,20 +272,16 @@ void ftmsbike::characteristicChanged(const QLowEnergyCharacteristic &characteris
|
||||
}
|
||||
|
||||
if (Flags.totDistance) {
|
||||
|
||||
/*
|
||||
* the distance sent from the most trainers is a total distance, so it's useless for QZ
|
||||
*
|
||||
Distance = ((double)((((uint32_t)((uint8_t)newValue.at(index + 2)) << 16) |
|
||||
(uint32_t)((uint8_t)newValue.at(index + 1)) << 8) |
|
||||
(uint32_t)((uint8_t)newValue.at(index)))) /
|
||||
1000.0;*/
|
||||
1000.0;
|
||||
index += 3;
|
||||
} else {
|
||||
Distance += ((Speed.value() / 3600000.0) *
|
||||
((double)lastRefreshCharacteristicChanged.msecsTo(QDateTime::currentDateTime())));
|
||||
}
|
||||
|
||||
Distance += ((Speed.value() / 3600000.0) *
|
||||
((double)lastRefreshCharacteristicChanged.msecsTo(now)));
|
||||
|
||||
emit debug(QStringLiteral("Current Distance: ") + QString::number(Distance.value()));
|
||||
|
||||
if (Flags.resistanceLvl) {
|
||||
@@ -306,8 +290,7 @@ void ftmsbike::characteristicChanged(const QLowEnergyCharacteristic &characteris
|
||||
emit resistanceRead(Resistance.value());
|
||||
index += 2;
|
||||
emit debug(QStringLiteral("Current Resistance: ") + QString::number(Resistance.value()));
|
||||
resistance_received = true;
|
||||
}
|
||||
} else {
|
||||
double ac = 0.01243107769;
|
||||
double bc = 1.145964912;
|
||||
double cc = -23.50977444;
|
||||
@@ -325,13 +308,10 @@ void ftmsbike::characteristicChanged(const QLowEnergyCharacteristic &characteris
|
||||
(2.0 * ar)) *
|
||||
settings.value(QZSettings::peloton_gain, QZSettings::default_peloton_gain).toDouble()) +
|
||||
settings.value(QZSettings::peloton_offset, QZSettings::default_peloton_offset).toDouble();
|
||||
if (!resistance_received) {
|
||||
Resistance = m_pelotonResistance;
|
||||
emit resistanceRead(Resistance.value());
|
||||
emit debug(QStringLiteral("Current Resistance: ") + QString::number(Resistance.value()));
|
||||
}
|
||||
Resistance = m_pelotonResistance;
|
||||
emit resistanceRead(Resistance.value());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (Flags.instantPower) {
|
||||
if (settings.value(QZSettings::power_sensor_name, QZSettings::default_power_sensor_name)
|
||||
@@ -368,7 +348,7 @@ void ftmsbike::characteristicChanged(const QLowEnergyCharacteristic &characteris
|
||||
200.0) /
|
||||
(60000.0 /
|
||||
((double)lastRefreshCharacteristicChanged.msecsTo(
|
||||
now)))); //(( (0.048* Output in watts +1.19) * body weight in
|
||||
QDateTime::currentDateTime())))); //(( (0.048* Output in watts +1.19) * body weight in
|
||||
// kg * 3.5) / 200 ) / 60
|
||||
}
|
||||
|
||||
@@ -381,7 +361,7 @@ void ftmsbike::characteristicChanged(const QLowEnergyCharacteristic &characteris
|
||||
#endif
|
||||
{
|
||||
if (Flags.heartRate && !disable_hr_frommachinery && newValue.length() > index) {
|
||||
Heart = ((double)(((uint8_t)newValue.at(index))));
|
||||
Heart = ((double)((newValue.at(index))));
|
||||
// index += 1; // NOTE: clang-analyzer-deadcode.DeadStores
|
||||
emit debug(QStringLiteral("Current Heart: ") + QString::number(Heart.value()));
|
||||
} else {
|
||||
@@ -439,7 +419,7 @@ void ftmsbike::characteristicChanged(const QLowEnergyCharacteristic &characteris
|
||||
} else {
|
||||
Speed = metric::calculateSpeedFromPower(
|
||||
watts(), Inclination.value(), Speed.value(),
|
||||
fabs(now.msecsTo(Speed.lastChanged()) / 1000.0), this->speedLimit());
|
||||
fabs(QDateTime::currentDateTime().msecsTo(Speed.lastChanged()) / 1000.0), this->speedLimit());
|
||||
}
|
||||
emit debug(QStringLiteral("Current Speed: ") + QString::number(Speed.value()));
|
||||
index += 2;
|
||||
@@ -462,7 +442,7 @@ void ftmsbike::characteristicChanged(const QLowEnergyCharacteristic &characteris
|
||||
index += 3;
|
||||
} else {
|
||||
Distance += ((Speed.value() / 3600000.0) *
|
||||
((double)lastRefreshCharacteristicChanged.msecsTo(now)));
|
||||
((double)lastRefreshCharacteristicChanged.msecsTo(QDateTime::currentDateTime())));
|
||||
}
|
||||
|
||||
emit debug(QStringLiteral("Current Distance: ") + QString::number(Distance.value()));
|
||||
@@ -558,7 +538,7 @@ void ftmsbike::characteristicChanged(const QLowEnergyCharacteristic &characteris
|
||||
200.0) /
|
||||
(60000.0 /
|
||||
((double)lastRefreshCharacteristicChanged.msecsTo(
|
||||
now)))); //(( (0.048* Output in watts +1.19) * body weight in
|
||||
QDateTime::currentDateTime())))); //(( (0.048* Output in watts +1.19) * body weight in
|
||||
// kg * 3.5) / 200 ) / 60
|
||||
}
|
||||
|
||||
@@ -571,7 +551,7 @@ void ftmsbike::characteristicChanged(const QLowEnergyCharacteristic &characteris
|
||||
#endif
|
||||
{
|
||||
if (Flags.heartRate && !disable_hr_frommachinery && newValue.length() > index) {
|
||||
Heart = ((double)(((uint8_t)newValue.at(index))));
|
||||
Heart = ((double)((newValue.at(index))));
|
||||
// index += 1; // NOTE: clang-analyzer-deadcode.DeadStores
|
||||
emit debug(QStringLiteral("Current Heart: ") + QString::number(Heart.value()));
|
||||
} else {
|
||||
@@ -600,7 +580,7 @@ void ftmsbike::characteristicChanged(const QLowEnergyCharacteristic &characteris
|
||||
LastCrankEventTime += (uint16_t)(1024.0 / (((double)(Cadence.value())) / 60.0));
|
||||
}
|
||||
|
||||
lastRefreshCharacteristicChanged = now;
|
||||
lastRefreshCharacteristicChanged = QDateTime::currentDateTime();
|
||||
|
||||
if (heartRateBeltName.startsWith(QStringLiteral("Disabled")) &&
|
||||
(!heart || Heart.value() == 0 || disable_hr_frommachinery)) {
|
||||
@@ -779,7 +759,7 @@ void ftmsbike::ftmsCharacteristicChanged(const QLowEnergyCharacteristic &charact
|
||||
qDebug() << "routing FTMS packet to the bike from virtualbike" << characteristic.uuid() << newValue.toHex(' ');
|
||||
|
||||
// handling gears
|
||||
if (b.at(0) == FTMS_SET_INDOOR_BIKE_SIMULATION_PARAMS) {
|
||||
if (b.at(0) == 0x11) {
|
||||
qDebug() << "applying gears mod" << m_gears;
|
||||
int16_t slope = (((uint8_t)b.at(3)) + (b.at(4) << 8));
|
||||
if (m_gears != 0) {
|
||||
@@ -867,9 +847,6 @@ void ftmsbike::deviceDiscovered(const QBluetoothDeviceInfo &device) {
|
||||
if (bluetoothDevice.name().toUpper().startsWith("SUITO")) {
|
||||
qDebug() << QStringLiteral("SUITO found");
|
||||
max_resistance = 16;
|
||||
} else if ((bluetoothDevice.name().toUpper().startsWith("MAGNUS "))) {
|
||||
qDebug() << QStringLiteral("MAGNUS found");
|
||||
resistance_lvl_mode = true;
|
||||
}
|
||||
|
||||
m_control = QLowEnergyController::createCentral(bluetoothDevice, this);
|
||||
|
||||
@@ -86,7 +86,7 @@ class ftmsbike : public bike {
|
||||
|
||||
QList<QLowEnergyService *> gattCommunicationChannelService;
|
||||
QLowEnergyCharacteristic gattWriteCharControlPointId;
|
||||
QLowEnergyService *gattFTMSService = nullptr;
|
||||
QLowEnergyService *gattFTMSService;
|
||||
|
||||
uint8_t sec1Update = 0;
|
||||
QByteArray lastPacket;
|
||||
@@ -104,9 +104,6 @@ class ftmsbike : public bike {
|
||||
|
||||
bool powerForced = false;
|
||||
|
||||
bool resistance_lvl_mode = false;
|
||||
bool resistance_received = false;
|
||||
|
||||
#ifdef Q_OS_IOS
|
||||
lockscreen *h = 0;
|
||||
#endif
|
||||
|
||||
@@ -54,7 +54,8 @@ void ftmsrower::writeCharacteristic(uint8_t *data, uint8_t data_len, const QStri
|
||||
gattFTMSService->writeCharacteristic(gattWriteCharControlPointId, *writeBuffer);
|
||||
|
||||
if (!disable_log) {
|
||||
emit debug(QStringLiteral(" >> ") + writeBuffer->toHex(' ') + QStringLiteral(" // ") + info);
|
||||
emit debug(QStringLiteral(" >> ") + writeBuffer->toHex(' ') +
|
||||
QStringLiteral(" // ") + info);
|
||||
}
|
||||
|
||||
loop.exec();
|
||||
@@ -136,7 +137,6 @@ void ftmsrower::serviceDiscovered(const QBluetoothUuid &gatt) {
|
||||
}
|
||||
|
||||
void ftmsrower::characteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &newValue) {
|
||||
QDateTime now = QDateTime::currentDateTime();
|
||||
|
||||
// qDebug() << "characteristicChanged" << characteristic.uuid() << newValue << newValue.length();
|
||||
Q_UNUSED(characteristic);
|
||||
@@ -186,11 +186,9 @@ void ftmsrower::characteristicChanged(const QLowEnergyCharacteristic &characteri
|
||||
|
||||
if (!Flags.moreData) {
|
||||
|
||||
if ((WATER_ROWER || DFIT_L_R) && lastStroke.secsTo(now) > 3) {
|
||||
if (WATER_ROWER && lastStroke.secsTo(QDateTime::currentDateTime()) > 3) {
|
||||
qDebug() << "Resetting cadence!";
|
||||
Cadence = 0;
|
||||
m_watt = 0;
|
||||
Speed = 0;
|
||||
} else {
|
||||
Cadence = ((uint8_t)newValue.at(index)) / cadence_divider;
|
||||
}
|
||||
@@ -199,7 +197,7 @@ void ftmsrower::characteristicChanged(const QLowEnergyCharacteristic &characteri
|
||||
(((uint16_t)((uint8_t)newValue.at(index + 2)) << 8) | (uint16_t)((uint8_t)newValue.at(index + 1)));
|
||||
|
||||
if (lastStrokesCount != StrokesCount.value()) {
|
||||
lastStroke = now;
|
||||
lastStroke = QDateTime::currentDateTime();
|
||||
}
|
||||
lastStrokesCount = StrokesCount.value();
|
||||
|
||||
@@ -231,7 +229,7 @@ void ftmsrower::characteristicChanged(const QLowEnergyCharacteristic &characteri
|
||||
index += 3;
|
||||
} else {
|
||||
Distance += ((Speed.value() / 3600000.0) *
|
||||
((double)lastRefreshCharacteristicChanged.msecsTo(now)));
|
||||
((double)lastRefreshCharacteristicChanged.msecsTo(QDateTime::currentDateTime())));
|
||||
}
|
||||
|
||||
emit debug(QStringLiteral("Current Distance: ") + QString::number(Distance.value()));
|
||||
@@ -244,10 +242,8 @@ void ftmsrower::characteristicChanged(const QLowEnergyCharacteristic &characteri
|
||||
index += 2;
|
||||
emit debug(QStringLiteral("Current Pace: ") + QString::number(instantPace));
|
||||
|
||||
if((DFIT_L_R && Cadence.value() > 0) || !DFIT_L_R) {
|
||||
Speed = (60.0 / instantPace) *
|
||||
Speed = (60.0 / instantPace) *
|
||||
30.0; // translating pace (min/500m) to km/h in order to match the pace function in the rower.cpp
|
||||
}
|
||||
emit debug(QStringLiteral("Current Speed: ") + QString::number(Speed.value()));
|
||||
}
|
||||
|
||||
@@ -265,8 +261,7 @@ void ftmsrower::characteristicChanged(const QLowEnergyCharacteristic &characteri
|
||||
((double)(((uint16_t)((uint8_t)newValue.at(index + 1)) << 8) | (uint16_t)((uint8_t)newValue.at(index))));
|
||||
index += 2;
|
||||
if (!filterWattNull || watt != 0) {
|
||||
if((DFIT_L_R && Cadence.value() > 0) || !DFIT_L_R)
|
||||
m_watt = watt;
|
||||
m_watt = watt;
|
||||
}
|
||||
emit debug(QStringLiteral("Current Watt: ") + QString::number(m_watt.value()));
|
||||
}
|
||||
@@ -304,7 +299,7 @@ void ftmsrower::characteristicChanged(const QLowEnergyCharacteristic &characteri
|
||||
settings.value(QZSettings::weight, QZSettings::default_weight).toFloat() * 3.5) /
|
||||
200.0) /
|
||||
(60000.0 / ((double)lastRefreshCharacteristicChanged.msecsTo(
|
||||
now)))); //(( (0.048* Output in watts +1.19) * body weight in
|
||||
QDateTime::currentDateTime())))); //(( (0.048* Output in watts +1.19) * body weight in
|
||||
// kg * 3.5) / 200 ) / 60
|
||||
}
|
||||
|
||||
@@ -347,7 +342,7 @@ void ftmsrower::characteristicChanged(const QLowEnergyCharacteristic &characteri
|
||||
LastCrankEventTime += (uint16_t)(1024.0 / (((double)(Cadence.value())) / 60.0));
|
||||
}
|
||||
|
||||
lastRefreshCharacteristicChanged = now;
|
||||
lastRefreshCharacteristicChanged = QDateTime::currentDateTime();
|
||||
|
||||
if (heartRateBeltName.startsWith(QStringLiteral("Disabled"))) {
|
||||
update_hr_from_external();
|
||||
@@ -471,8 +466,6 @@ void ftmsrower::stateChanged(QLowEnergyService::ServiceState state) {
|
||||
QSettings settings;
|
||||
bool virtual_device_enabled =
|
||||
settings.value(QZSettings::virtual_device_enabled, QZSettings::default_virtual_device_enabled).toBool();
|
||||
bool virtual_device_rower =
|
||||
settings.value(QZSettings::virtual_device_rower, QZSettings::default_virtual_device_rower).toBool();
|
||||
#ifdef Q_OS_IOS
|
||||
#ifndef IO_UNDER_QT
|
||||
bool cadence =
|
||||
@@ -488,25 +481,16 @@ void ftmsrower::stateChanged(QLowEnergyService::ServiceState state) {
|
||||
|
||||
#endif
|
||||
#endif
|
||||
{
|
||||
if (virtual_device_enabled) {
|
||||
if (!virtual_device_rower) {
|
||||
emit debug(QStringLiteral("creating virtual bike interface..."));
|
||||
emit debug(QStringLiteral("creating virtual bike interface..."));
|
||||
|
||||
auto virtualBike = new virtualbike(this, noWriteResistance, noHeartService);
|
||||
// connect(virtualBike,&virtualbike::debug ,this,&ftmsrower::debug);
|
||||
this->setVirtualDevice(virtualBike, VIRTUAL_DEVICE_MODE::PRIMARY);
|
||||
} else {
|
||||
qDebug() << QStringLiteral("creating virtual rower interface...");
|
||||
auto virtualRower = new virtualrower(this, noWriteResistance, noHeartService);
|
||||
// connect(virtualRower,&virtualrower::debug ,this,&echelonrower::debug);
|
||||
this->setVirtualDevice(virtualRower, VIRTUAL_DEVICE_MODE::PRIMARY);
|
||||
}
|
||||
}
|
||||
auto virtualBike = new virtualbike(this, noWriteResistance, noHeartService);
|
||||
// connect(virtualBike,&virtualbike::debug ,this,&ftmsrower::debug);
|
||||
this->setVirtualDevice(virtualBike, VIRTUAL_DEVICE_MODE::PRIMARY);
|
||||
}
|
||||
firstStateChanged = 1;
|
||||
// ********************************************************************************************************
|
||||
}
|
||||
firstStateChanged = 1;
|
||||
// ********************************************************************************************************
|
||||
}
|
||||
|
||||
void ftmsrower::descriptorWritten(const QLowEnergyDescriptor &descriptor, const QByteArray &newValue) {
|
||||
@@ -580,9 +564,6 @@ void ftmsrower::deviceDiscovered(const QBluetoothDeviceInfo &device) {
|
||||
} else if (device.name().toUpper().startsWith(QStringLiteral("S4 COMMS"))) {
|
||||
WATER_ROWER = true;
|
||||
qDebug() << "WATER_ROWER found!";
|
||||
} else if (device.name().toUpper().startsWith(QStringLiteral("DFIT-L-R"))) {
|
||||
DFIT_L_R = true;
|
||||
qDebug() << "DFIT_L_R found!";
|
||||
} else if (device.name().toUpper().startsWith(QStringLiteral("PM5"))) {
|
||||
PM5 = true;
|
||||
qDebug() << "PM5 found!";
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
|
||||
#include "rower.h"
|
||||
#include "virtualbike.h"
|
||||
#include "virtualrower.h"
|
||||
|
||||
#ifdef Q_OS_IOS
|
||||
#include "ios/lockscreen.h"
|
||||
@@ -70,7 +69,6 @@ class ftmsrower : public rower {
|
||||
bool PM5 = false;
|
||||
|
||||
bool WATER_ROWER = false;
|
||||
bool DFIT_L_R = false;
|
||||
QDateTime lastStroke = QDateTime::currentDateTime();
|
||||
double lastStrokesCount = 0;
|
||||
|
||||
|
||||
@@ -7,16 +7,12 @@
|
||||
|
||||
gpx::gpx(QObject *parent) : QObject(parent) {}
|
||||
|
||||
QList<gpx_altitude_point_for_treadmill> gpx::open(const QString &gpx, bluetoothdevice::BLUETOOTH_TYPE device_type) {
|
||||
QList<gpx_altitude_point_for_treadmill> gpx::open(const QString &gpx) {
|
||||
QSettings settings;
|
||||
const double meter_limit_for_auto_loop = 300;
|
||||
bool treadmill_force_speed =
|
||||
settings.value(QZSettings::treadmill_force_speed, QZSettings::default_treadmill_force_speed).toBool();
|
||||
bool gpx_loop = settings.value(QZSettings::gpx_loop, QZSettings::default_gpx_loop).toBool();
|
||||
|
||||
if(device_type == bluetoothdevice::BIKE)
|
||||
treadmill_force_speed = false;
|
||||
|
||||
QFile input(gpx);
|
||||
input.open(QIODevice::ReadOnly);
|
||||
QDomDocument doc;
|
||||
|
||||
@@ -29,7 +29,7 @@ class gpx : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit gpx(QObject *parent = nullptr);
|
||||
QList<gpx_altitude_point_for_treadmill> open(const QString &gpx, bluetoothdevice::BLUETOOTH_TYPE device_type);
|
||||
QList<gpx_altitude_point_for_treadmill> open(const QString &gpx);
|
||||
static void save(const QString &filename, QList<SessionLine> session, bluetoothdevice::BLUETOOTH_TYPE type);
|
||||
QString getVideoURL() {return videoUrl;}
|
||||
|
||||
|
||||
449
src/homeform.cpp
449
src/homeform.cpp
@@ -5,7 +5,6 @@
|
||||
#include "localipaddress.h"
|
||||
#ifdef Q_OS_ANDROID
|
||||
#include "keepawakehelper.h"
|
||||
#include <QAndroidJniObject>
|
||||
#endif
|
||||
#include "material.h"
|
||||
#include "qfit.h"
|
||||
@@ -48,12 +47,23 @@ using namespace std::chrono_literals;
|
||||
#include <QtAndroid>
|
||||
#endif
|
||||
|
||||
#if __has_include("secret.h")
|
||||
#include "secret.h"
|
||||
#else
|
||||
#define STRAVA_SECRET_KEY test
|
||||
#if defined(WIN32)
|
||||
#pragma message("DEFINE STRAVA_SECRET_KEY!!!")
|
||||
#else
|
||||
#warning "DEFINE STRAVA_SECRET_KEY!!!"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef STRAVA_CLIENT_ID
|
||||
#define STRAVA_CLIENT_ID 7976
|
||||
#if defined(WIN32)
|
||||
#pragma message("DEFINE STRAVA_CLIENT_ID!!!")
|
||||
#else
|
||||
#pragma message "DEFINE STRAVA_CLIENT_ID!!!"
|
||||
#warning "DEFINE STRAVA_CLIENT_ID!!!"
|
||||
#endif
|
||||
#endif
|
||||
#define _STR(x) #x
|
||||
@@ -475,9 +485,6 @@ homeform::homeform(QQmlApplicationEngine *engine, bluetooth *bl) {
|
||||
QObject::connect(home, SIGNAL(start_clicked()), this, SLOT(Start()));
|
||||
QObject::connect(home, SIGNAL(stop_clicked()), this, SLOT(Stop()));
|
||||
QObject::connect(stack, SIGNAL(trainprogram_open_clicked(QUrl)), this, SLOT(trainprogram_open_clicked(QUrl)));
|
||||
QObject::connect(stack, SIGNAL(trainprogram_open_other_folder(QUrl)), this, SLOT(trainprogram_open_other_folder(QUrl)));
|
||||
QObject::connect(stack, SIGNAL(gpx_open_other_folder(QUrl)), this, SLOT(gpx_open_other_folder(QUrl)));
|
||||
QObject::connect(stack, SIGNAL(profile_open_clicked(QUrl)), this, SLOT(profile_open_clicked(QUrl)));
|
||||
QObject::connect(stack, SIGNAL(trainprogram_preview(QUrl)), this, SLOT(trainprogram_preview(QUrl)));
|
||||
QObject::connect(stack, SIGNAL(gpxpreview_open_clicked(QUrl)), this, SLOT(gpxpreview_open_clicked(QUrl)));
|
||||
QObject::connect(stack, SIGNAL(trainprogram_zwo_loaded(QString)), this, SLOT(trainprogram_zwo_loaded(QString)));
|
||||
@@ -543,22 +550,6 @@ homeform::homeform(QQmlApplicationEngine *engine, bluetooth *bl) {
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef Q_OS_ANDROID
|
||||
// Android 14 restrics access to /Android/data folder
|
||||
if (QOperatingSystemVersion::current() >= QOperatingSystemVersion(QOperatingSystemVersion::Android, 14)) {
|
||||
QDirIterator itAndroid(getAndroidDataAppDir(), QDirIterator::Subdirectories);
|
||||
QDir().mkdir(getWritableAppDir());
|
||||
QDir().mkdir(getProfileDir());
|
||||
while (itAndroid.hasNext()) {
|
||||
qDebug() << itAndroid.filePath() << itAndroid.fileName() << itAndroid.filePath().replace(itAndroid.path(), "");
|
||||
if (!QFile(getWritableAppDir() + itAndroid.next().replace(itAndroid.path(), "")).exists()) {
|
||||
if(QFile::copy(itAndroid.filePath(), getWritableAppDir() + itAndroid.filePath().replace(itAndroid.path(), "")))
|
||||
QFile::remove(itAndroid.filePath());
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
m_speech.setLocale(QLocale::English);
|
||||
|
||||
#if defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)
|
||||
@@ -566,12 +557,14 @@ homeform::homeform(QQmlApplicationEngine *engine, bluetooth *bl) {
|
||||
deviceConnected(b);
|
||||
#endif
|
||||
|
||||
if (settings.value(QZSettings::peloton_bike_ocr, QZSettings::default_peloton_bike_ocr).toBool()) {
|
||||
// TO RESTORE
|
||||
if (settings.value(QZSettings::peloton_bike_ocr, QZSettings::default_peloton_bike_ocr).toBool() ||
|
||||
settings.value(QZSettings::fakedevice_treadmill, QZSettings::default_fakedevice_treadmill).toBool()) {
|
||||
QBluetoothDeviceInfo b;
|
||||
deviceConnected(b);
|
||||
}
|
||||
|
||||
#ifndef Q_OS_IOS
|
||||
#ifdef Q_OS_ANDROID
|
||||
iphone_browser = new QMdnsEngine::Browser(&iphone_server, "_qz_iphone._tcp.local.", &iphone_cache);
|
||||
|
||||
QObject::connect(iphone_browser, &QMdnsEngine::Browser::serviceAdded, [](const QMdnsEngine::Service &service) {
|
||||
@@ -661,12 +654,8 @@ void homeform::chartSaved(QString fileName) {
|
||||
if (!stopped)
|
||||
return;
|
||||
chartImagesFilenames.append(fileName);
|
||||
if (chartImagesFilenames.length() >= 9) {
|
||||
if (chartImagesFilenames.length() >= 8) {
|
||||
sendMail();
|
||||
qDebug() << "removing chart images";
|
||||
for (const QString &f : qAsConst(chartImagesFilenames)) {
|
||||
QFile::remove(f);
|
||||
}
|
||||
chartImagesFilenames.clear();
|
||||
}
|
||||
}
|
||||
@@ -773,7 +762,7 @@ void homeform::peloton_start_workout() {
|
||||
if (!stravaPelotonActivityName.isEmpty() && !stravaPelotonInstructorName.isEmpty()) {
|
||||
QString path = getWritableAppDir() + "training/" + workoutNameBasedOnBluetoothDevice() + "/" +
|
||||
stravaPelotonInstructorName + "/";
|
||||
QDir().mkpath(path);
|
||||
QDir().mkdir(path);
|
||||
lastTrainProgramFileSaved =
|
||||
path + stravaPelotonActivityName.replace("/", "-") + " - " + stravaPelotonInstructorName + ".xml";
|
||||
trainProgram->save(lastTrainProgramFileSaved);
|
||||
@@ -864,13 +853,7 @@ void homeform::pelotonWorkoutChanged(const QString &name, const QString &instruc
|
||||
QString homeform::getWritableAppDir() {
|
||||
QString path = QLatin1String("");
|
||||
#if defined(Q_OS_ANDROID)
|
||||
// Android 14 restrics access to /Android/data folder
|
||||
if (QOperatingSystemVersion::current() >= QOperatingSystemVersion(QOperatingSystemVersion::Android, 14)) {
|
||||
path = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation) + "/QZ/";
|
||||
QDir().mkdir(path);
|
||||
} else {
|
||||
path = getAndroidDataAppDir() + "/";
|
||||
}
|
||||
path = getAndroidDataAppDir() + "/";
|
||||
#elif defined(Q_OS_MACOS) || defined(Q_OS_OSX)
|
||||
path = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation) + "/";
|
||||
#elif defined(Q_OS_IOS)
|
||||
@@ -894,7 +877,7 @@ void homeform::backup() {
|
||||
QFile::remove(filename);
|
||||
qfit::save(filename, Session, dev->deviceType(),
|
||||
qobject_cast<m3ibike *>(dev) ? QFIT_PROCESS_DISTANCENOISE : QFIT_PROCESS_NONE,
|
||||
stravaPelotonWorkoutType, dev->bluetoothDevice.name());
|
||||
stravaPelotonWorkoutType);
|
||||
|
||||
index++;
|
||||
if (index > 1) {
|
||||
@@ -1057,19 +1040,6 @@ void homeform::trainProgramSignals() {
|
||||
connect(this, &homeform::workoutEventStateChanged, bluetoothManager->device(),
|
||||
&bluetoothdevice::workoutEventStateChanged);
|
||||
|
||||
if (trainProgram) {
|
||||
setChartIconVisible(trainProgram->powerzoneWorkout());
|
||||
if (chartFooterVisible()) {
|
||||
if (trainProgram->powerzoneWorkout()) {
|
||||
// reloading
|
||||
setChartFooterVisible(false);
|
||||
setChartFooterVisible(true);
|
||||
} else {
|
||||
setChartFooterVisible(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
qDebug() << QStringLiteral("trainProgram associated to a device");
|
||||
} else {
|
||||
qDebug() << QStringLiteral("trainProgram NOT associated to a device");
|
||||
@@ -1973,57 +1943,6 @@ void homeform::sortTiles() {
|
||||
target_pace->setName("T.Pace(m/500m)");
|
||||
dataList.append(target_pace);
|
||||
}
|
||||
|
||||
if (settings
|
||||
.value(QZSettings::tile_preset_resistance_1_enabled,
|
||||
QZSettings::default_tile_preset_resistance_1_enabled)
|
||||
.toBool() &&
|
||||
settings.value(QZSettings::tile_preset_resistance_1_order,
|
||||
QZSettings::default_tile_preset_resistance_1_order)
|
||||
.toInt() == i) {
|
||||
preset_resistance_1->setGridId(i);
|
||||
dataList.append(preset_resistance_1);
|
||||
}
|
||||
if (settings
|
||||
.value(QZSettings::tile_preset_resistance_2_enabled,
|
||||
QZSettings::default_tile_preset_resistance_2_enabled)
|
||||
.toBool() &&
|
||||
settings.value(QZSettings::tile_preset_resistance_2_order,
|
||||
QZSettings::default_tile_preset_resistance_2_order)
|
||||
.toInt() == i) {
|
||||
preset_resistance_2->setGridId(i);
|
||||
dataList.append(preset_resistance_2);
|
||||
}
|
||||
if (settings
|
||||
.value(QZSettings::tile_preset_resistance_3_enabled,
|
||||
QZSettings::default_tile_preset_resistance_3_enabled)
|
||||
.toBool() &&
|
||||
settings.value(QZSettings::tile_preset_resistance_3_order,
|
||||
QZSettings::default_tile_preset_resistance_3_order)
|
||||
.toInt() == i) {
|
||||
preset_resistance_3->setGridId(i);
|
||||
dataList.append(preset_resistance_3);
|
||||
}
|
||||
if (settings
|
||||
.value(QZSettings::tile_preset_resistance_4_enabled,
|
||||
QZSettings::default_tile_preset_resistance_4_enabled)
|
||||
.toBool() &&
|
||||
settings.value(QZSettings::tile_preset_resistance_4_order,
|
||||
QZSettings::default_tile_preset_resistance_4_order)
|
||||
.toInt() == i) {
|
||||
preset_resistance_4->setGridId(i);
|
||||
dataList.append(preset_resistance_4);
|
||||
}
|
||||
if (settings
|
||||
.value(QZSettings::tile_preset_resistance_5_enabled,
|
||||
QZSettings::default_tile_preset_resistance_5_enabled)
|
||||
.toBool() &&
|
||||
settings.value(QZSettings::tile_preset_resistance_5_order,
|
||||
QZSettings::default_tile_preset_resistance_5_order)
|
||||
.toInt() == i) {
|
||||
preset_resistance_5->setGridId(i);
|
||||
dataList.append(preset_resistance_5);
|
||||
}
|
||||
}
|
||||
} else if (bluetoothManager->device()->deviceType() == bluetoothdevice::ELLIPTICAL) {
|
||||
for (int i = 0; i < 100; i++) {
|
||||
@@ -2325,12 +2244,6 @@ void homeform::sortTiles() {
|
||||
target_pace->setGridId(i);
|
||||
dataList.append(target_pace);
|
||||
}
|
||||
|
||||
if (settings.value(QZSettings::tile_pace_enabled, true).toBool() &&
|
||||
settings.value(QZSettings::tile_pace_order, 51).toInt() == i) {
|
||||
pace->setGridId(i);
|
||||
dataList.append(pace);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2436,14 +2349,6 @@ void homeform::deviceConnected(QBluetoothDeviceInfo b) {
|
||||
if (settings.value(QZSettings::floating_startup, QZSettings::default_floating_startup).toBool()) {
|
||||
floatingOpen();
|
||||
}
|
||||
|
||||
if (!settings.value(QZSettings::heart_rate_belt_name, QZSettings::default_heart_rate_belt_name)
|
||||
.toString()
|
||||
.compare(QZSettings::default_heart_rate_belt_name) &&
|
||||
!settings.value(QZSettings::ant_heart, QZSettings::default_ant_heart).toBool()) {
|
||||
QAndroidJniObject::callStaticMethod<void>("org/cagnulen/qdomyoszwift/WearableController", "start",
|
||||
"(Landroid/content/Context;)V", QtAndroid::androidContext().object());
|
||||
}
|
||||
#endif
|
||||
|
||||
if (settings.value(QZSettings::gears_restore_value, QZSettings::default_gears_restore_value).toBool()) {
|
||||
@@ -2907,7 +2812,6 @@ void homeform::Plus(const QString &name) {
|
||||
} else if (name.contains(QStringLiteral("target_power"))) {
|
||||
if (bluetoothManager->device()) {
|
||||
if (bluetoothManager->device()->deviceType() == bluetoothdevice::BIKE) {
|
||||
m_overridePower = true;
|
||||
((bike *)bluetoothManager->device())
|
||||
->changePower(((bike *)bluetoothManager->device())->lastRequestedPower().value() + 10);
|
||||
if (trainProgram) {
|
||||
@@ -2953,8 +2857,8 @@ void homeform::pelotonOffset_Minus() { Minus(QStringLiteral("peloton_offset"));
|
||||
void homeform::bluetoothDeviceConnected(bluetoothdevice *b) {
|
||||
this->innerTemplateManager->start(b);
|
||||
this->userTemplateManager->start(b);
|
||||
#ifndef Q_OS_IOS
|
||||
// heart rate received from apple watch while QZ is running on a different device via TCP socket (iphone_socket)
|
||||
#ifdef Q_OS_ANDROID
|
||||
// heart rate received from apple watch while QZ is running on android via TCP socket (iphone_socket)
|
||||
connect(this, SIGNAL(heartRate(uint8_t)), b, SLOT(heartRate(uint8_t)));
|
||||
#endif
|
||||
}
|
||||
@@ -3149,7 +3053,6 @@ void homeform::Minus(const QString &name) {
|
||||
} else if (name.contains(QStringLiteral("target_power"))) {
|
||||
if (bluetoothManager->device()) {
|
||||
if (bluetoothManager->device()->deviceType() == bluetoothdevice::BIKE) {
|
||||
m_overridePower = true;
|
||||
((bike *)bluetoothManager->device())
|
||||
->changePower(((bike *)bluetoothManager->device())->lastRequestedPower().value() - 10);
|
||||
if (trainProgram) {
|
||||
@@ -3197,8 +3100,6 @@ void homeform::Start_inner(bool send_event_to_device) {
|
||||
QSettings settings;
|
||||
qDebug() << QStringLiteral("Start pressed - paused") << paused << QStringLiteral("stopped") << stopped;
|
||||
|
||||
m_overridePower = false;
|
||||
|
||||
if (settings.value(QZSettings::tts_enabled, QZSettings::default_tts_enabled).toBool())
|
||||
m_speech.say("Start pressed");
|
||||
|
||||
@@ -3303,9 +3204,6 @@ void homeform::StopRequested() {
|
||||
|
||||
void homeform::Stop() {
|
||||
QSettings settings;
|
||||
|
||||
m_startRequested = false;
|
||||
|
||||
qDebug() << QStringLiteral("Stop pressed - paused") << paused << QStringLiteral("stopped") << stopped;
|
||||
|
||||
if (stopped) {
|
||||
@@ -3356,10 +3254,6 @@ void homeform::Stop() {
|
||||
emit startIconChanged(startIcon());
|
||||
emit startTextChanged(startText());
|
||||
emit startColorChanged(startColor());
|
||||
|
||||
// clearing the label on top because if it was running a training program, with stop the program will be terminated
|
||||
m_info = workoutName();
|
||||
emit infoChanged(m_info);
|
||||
}
|
||||
|
||||
if (trainProgram) {
|
||||
@@ -3568,7 +3462,7 @@ void homeform::update() {
|
||||
else if (next.speed != -1)
|
||||
nextRows->setValue(QStringLiteral("S") + QString::number(next.speed) + QStringLiteral(" ") +
|
||||
next.duration.toString(QStringLiteral("mm:ss")));
|
||||
else if (next.inclination != -200)
|
||||
else if (next.inclination != -1)
|
||||
nextRows->setValue(QStringLiteral("I") + QString::number(next.inclination) + QStringLiteral(" ") +
|
||||
next.duration.toString(QStringLiteral("mm:ss")));
|
||||
else if (next.power != -1) {
|
||||
@@ -3641,22 +3535,7 @@ void homeform::update() {
|
||||
wattKg->setSecondLine(
|
||||
QStringLiteral("AVG: ") + QString::number(bluetoothManager->device()->wattKg().average(), 'f', 1) +
|
||||
QStringLiteral("MAX: ") + QString::number(bluetoothManager->device()->wattKg().max(), 'f', 1));
|
||||
QLocale locale = QLocale::system();
|
||||
|
||||
// Format the time based on the locale
|
||||
QString timeFormat = locale.timeFormat(QLocale::ShortFormat);
|
||||
bool usesAMPMFormat = timeFormat.toUpper().contains("A");
|
||||
QDateTime currentTime = QDateTime::currentDateTime();
|
||||
|
||||
QString formattedTime;
|
||||
if (usesAMPMFormat) {
|
||||
// The locale uses 12-hour format with AM/PM
|
||||
formattedTime = currentTime.toString("h:mm:ss AP");
|
||||
} else {
|
||||
// The locale uses 24-hour format
|
||||
formattedTime = currentTime.toString("H:mm:ss");
|
||||
}
|
||||
datetime->setValue(formattedTime);
|
||||
datetime->setValue(QTime::currentTime().toString(QStringLiteral("hh:mm:ss")));
|
||||
if (power5s)
|
||||
watts = bluetoothManager->device()->wattsMetric().average5s();
|
||||
else
|
||||
@@ -3761,46 +3640,29 @@ void homeform::update() {
|
||||
QStringLiteral(" MAX: ") +
|
||||
QString::number(((treadmill *)bluetoothManager->device())->currentVerticalOscillation().max(), 'f', 0));
|
||||
|
||||
// if there is no training program, the color is based on presets
|
||||
if (!trainProgram || trainProgram->currentRow().speed == -1) {
|
||||
if (bluetoothManager->device()->currentSpeed().value() < 9) {
|
||||
speed->setValueFontColor(QStringLiteral("white"));
|
||||
this->pace->setValueFontColor(QStringLiteral("white"));
|
||||
} else if (bluetoothManager->device()->currentSpeed().value() < 10) {
|
||||
speed->setValueFontColor(QStringLiteral("limegreen"));
|
||||
this->pace->setValueFontColor(QStringLiteral("limegreen"));
|
||||
} else if (bluetoothManager->device()->currentSpeed().value() < 11) {
|
||||
speed->setValueFontColor(QStringLiteral("gold"));
|
||||
this->pace->setValueFontColor(QStringLiteral("gold"));
|
||||
} else if (bluetoothManager->device()->currentSpeed().value() < 12) {
|
||||
speed->setValueFontColor(QStringLiteral("orange"));
|
||||
this->pace->setValueFontColor(QStringLiteral("orange"));
|
||||
} else if (bluetoothManager->device()->currentSpeed().value() < 13) {
|
||||
speed->setValueFontColor(QStringLiteral("darkorange"));
|
||||
this->pace->setValueFontColor(QStringLiteral("darkorange"));
|
||||
} else if (bluetoothManager->device()->currentSpeed().value() < 14) {
|
||||
speed->setValueFontColor(QStringLiteral("orangered"));
|
||||
this->pace->setValueFontColor(QStringLiteral("orangered"));
|
||||
} else {
|
||||
speed->setValueFontColor(QStringLiteral("red"));
|
||||
this->pace->setValueFontColor(QStringLiteral("red"));
|
||||
}
|
||||
if (bluetoothManager->device()->currentSpeed().value() < 9) {
|
||||
speed->setValueFontColor(QStringLiteral("white"));
|
||||
this->pace->setValueFontColor(QStringLiteral("white"));
|
||||
} else if (bluetoothManager->device()->currentSpeed().value() < 10) {
|
||||
speed->setValueFontColor(QStringLiteral("limegreen"));
|
||||
this->pace->setValueFontColor(QStringLiteral("limegreen"));
|
||||
} else if (bluetoothManager->device()->currentSpeed().value() < 11) {
|
||||
speed->setValueFontColor(QStringLiteral("gold"));
|
||||
this->pace->setValueFontColor(QStringLiteral("gold"));
|
||||
} else if (bluetoothManager->device()->currentSpeed().value() < 12) {
|
||||
speed->setValueFontColor(QStringLiteral("orange"));
|
||||
this->pace->setValueFontColor(QStringLiteral("orange"));
|
||||
} else if (bluetoothManager->device()->currentSpeed().value() < 13) {
|
||||
speed->setValueFontColor(QStringLiteral("darkorange"));
|
||||
this->pace->setValueFontColor(QStringLiteral("darkorange"));
|
||||
} else if (bluetoothManager->device()->currentSpeed().value() < 14) {
|
||||
speed->setValueFontColor(QStringLiteral("orangered"));
|
||||
this->pace->setValueFontColor(QStringLiteral("orangered"));
|
||||
} else {
|
||||
if (bluetoothManager->device()->currentSpeed().value() <= trainProgram->currentRow().upper_speed &&
|
||||
bluetoothManager->device()->currentSpeed().value() >= trainProgram->currentRow().lower_speed) {
|
||||
this->target_zone->setValueFontColor(QStringLiteral("limegreen"));
|
||||
this->pace->setValueFontColor(QStringLiteral("limegreen"));
|
||||
} else if (bluetoothManager->device()->currentSpeed().value() <=
|
||||
(trainProgram->currentRow().upper_speed + 0.2) &&
|
||||
bluetoothManager->device()->currentSpeed().value() >=
|
||||
(trainProgram->currentRow().lower_speed - 0.2)) {
|
||||
this->target_zone->setValueFontColor(QStringLiteral("orange"));
|
||||
this->pace->setValueFontColor(QStringLiteral("orange"));
|
||||
} else {
|
||||
this->target_zone->setValueFontColor(QStringLiteral("red"));
|
||||
this->pace->setValueFontColor(QStringLiteral("red"));
|
||||
}
|
||||
speed->setValueFontColor(QStringLiteral("red"));
|
||||
this->pace->setValueFontColor(QStringLiteral("red"));
|
||||
}
|
||||
bluetoothManager->device()->currentSpeed().setColor(speed->valueFontColor());
|
||||
|
||||
this->target_pace->setValue(
|
||||
((treadmill *)bluetoothManager->device())->lastRequestedPace().toString(QStringLiteral("m:ss")));
|
||||
@@ -3896,14 +3758,6 @@ void homeform::update() {
|
||||
this->steeringAngle->setValue(
|
||||
QString::number(((bike *)bluetoothManager->device())->currentSteeringAngle().value(), 'f', 1));
|
||||
|
||||
if ((!trainProgram || (trainProgram && !trainProgram->isStarted())) &&
|
||||
!((bike *)bluetoothManager->device())->ergModeSupportedAvailableByHardware() &&
|
||||
((bike *)bluetoothManager->device())->lastRequestedPower().value() > 0 && m_overridePower) {
|
||||
qDebug() << QStringLiteral("using target power tile for ERG workout manually");
|
||||
((bike *)bluetoothManager->device())
|
||||
->changePower(((bike *)bluetoothManager->device())->lastRequestedPower().value());
|
||||
}
|
||||
|
||||
} else if (bluetoothManager->device()->deviceType() == bluetoothdevice::ROWING) {
|
||||
if (bluetoothManager->device()->currentSpeed().value()) {
|
||||
pace = 10000 / (((rower *)bluetoothManager->device())->currentPace().second() +
|
||||
@@ -3957,23 +3811,17 @@ void homeform::update() {
|
||||
}
|
||||
switch (trainProgram->currentRow().pace_intensity) {
|
||||
case 0:
|
||||
this->target_zone->setValue(tr("Rec."));
|
||||
break;
|
||||
case 1:
|
||||
this->target_zone->setValue(tr("Easy"));
|
||||
break;
|
||||
case 2:
|
||||
case 1:
|
||||
this->target_zone->setValue(tr("Moder."));
|
||||
break;
|
||||
case 3:
|
||||
case 2:
|
||||
this->target_zone->setValue(tr("Chall."));
|
||||
break;
|
||||
case 4:
|
||||
case 3:
|
||||
this->target_zone->setValue(tr("Max"));
|
||||
break;
|
||||
default:
|
||||
this->target_zone->setValue(tr("N/A"));
|
||||
break;
|
||||
}
|
||||
}
|
||||
odometer->setValue(QString::number(bluetoothManager->device()->odometer() * 1000.0, 'f', 0));
|
||||
@@ -4051,19 +3899,10 @@ void homeform::update() {
|
||||
speed->setValueFontColor(QStringLiteral("red"));
|
||||
this->pace->setValueFontColor(QStringLiteral("red"));
|
||||
}
|
||||
bluetoothManager->device()->currentSpeed().setColor(speed->valueFontColor());
|
||||
}
|
||||
} else if (bluetoothManager->device()->deviceType() == bluetoothdevice::ELLIPTICAL) {
|
||||
|
||||
if (((elliptical *)bluetoothManager->device())->currentSpeed().value() > 2)
|
||||
this->pace->setValue(
|
||||
((elliptical *)bluetoothManager->device())->currentPace().toString(QStringLiteral("m:ss")));
|
||||
else
|
||||
this->pace->setValue("N/A");
|
||||
this->pace->setSecondLine(
|
||||
QStringLiteral("AVG: ") +
|
||||
((elliptical *)bluetoothManager->device())->averagePace().toString(QStringLiteral("m:ss")) +
|
||||
QStringLiteral(" MAX: ") +
|
||||
((elliptical *)bluetoothManager->device())->maxPace().toString(QStringLiteral("m:ss")));
|
||||
odometer->setValue(QString::number(bluetoothManager->device()->odometer() * unit_conversion, 'f', 2));
|
||||
resistance = ((elliptical *)bluetoothManager->device())->currentResistance().value();
|
||||
peloton_resistance = ((elliptical *)bluetoothManager->device())->pelotonResistance().value();
|
||||
@@ -4116,18 +3955,6 @@ void homeform::update() {
|
||||
if (trainProgram) {
|
||||
int8_t lower_requested_peloton_resistance = trainProgram->currentRow().lower_requested_peloton_resistance;
|
||||
int8_t upper_requested_peloton_resistance = trainProgram->currentRow().upper_requested_peloton_resistance;
|
||||
double lower_requested_peloton_resistance_to_bike_resistance = 0;
|
||||
if (bluetoothManager->device()->deviceType() == bluetoothdevice::BIKE)
|
||||
lower_requested_peloton_resistance_to_bike_resistance =
|
||||
((bike *)bluetoothManager->device())->pelotonToBikeResistance(lower_requested_peloton_resistance);
|
||||
else if (bluetoothManager->device()->deviceType() == bluetoothdevice::ROWING)
|
||||
lower_requested_peloton_resistance_to_bike_resistance =
|
||||
((rower *)bluetoothManager->device())->pelotonToBikeResistance(lower_requested_peloton_resistance);
|
||||
else if (bluetoothManager->device()->deviceType() == bluetoothdevice::ELLIPTICAL)
|
||||
lower_requested_peloton_resistance_to_bike_resistance =
|
||||
((elliptical *)bluetoothManager->device())
|
||||
->pelotonToEllipticalResistance(lower_requested_peloton_resistance);
|
||||
|
||||
if (lower_requested_peloton_resistance != -1) {
|
||||
this->target_peloton_resistance->setSecondLine(
|
||||
QStringLiteral("MIN: ") + QString::number(lower_requested_peloton_resistance, 'f', 0) +
|
||||
@@ -4142,16 +3969,17 @@ void homeform::update() {
|
||||
.toBool()) {
|
||||
if (lower_requested_peloton_resistance == -1) {
|
||||
this->peloton_resistance->setValueFontColor(QStringLiteral("white"));
|
||||
} else if (resistance < lower_requested_peloton_resistance_to_bike_resistance) {
|
||||
// we need to compare the real resistance and not the peloton resistance because most of the bikes
|
||||
// have a 1:3 conversion so this compare will be always true even if the actual resistance is the
|
||||
// same #1608
|
||||
} else if (((int8_t)qRound(peloton_resistance)) < lower_requested_peloton_resistance) {
|
||||
this->peloton_resistance->setValueFontColor(QStringLiteral("red"));
|
||||
} else if (((int8_t)qRound(peloton_resistance)) <= upper_requested_peloton_resistance) {
|
||||
this->peloton_resistance->setValueFontColor(QStringLiteral("limegreen"));
|
||||
} else {
|
||||
this->peloton_resistance->setValueFontColor(QStringLiteral("orange"));
|
||||
}
|
||||
if (bluetoothManager->device()->deviceType() == bluetoothdevice::BIKE)
|
||||
((bike *)bluetoothManager->device())
|
||||
->pelotonResistance()
|
||||
.setColor(this->peloton_resistance->valueFontColor());
|
||||
}
|
||||
|
||||
int16_t lower_cadence = trainProgram->currentRow().lower_cadence;
|
||||
@@ -4174,6 +4002,7 @@ void homeform::update() {
|
||||
} else {
|
||||
this->cadence->setValueFontColor(QStringLiteral("orange"));
|
||||
}
|
||||
bluetoothManager->device()->currentCadence().setColor(this->cadence->valueFontColor());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4269,6 +4098,7 @@ void homeform::update() {
|
||||
ftp->setValueFontColor(QStringLiteral("red"));
|
||||
watt->setValueFontColor(QStringLiteral("red"));
|
||||
}
|
||||
bluetoothManager->device()->wattsMetric().setColor(watt->valueFontColor());
|
||||
bluetoothManager->device()->setPowerZone(ftpZone);
|
||||
ftp->setValue(QStringLiteral("Z") + QString::number(ftpZone, 'f', 1));
|
||||
ftp->setSecondLine(ftpMinW + QStringLiteral("-") + ftpMaxW + QStringLiteral("W ") +
|
||||
@@ -4466,6 +4296,7 @@ void homeform::update() {
|
||||
pidHR->setValueFontColor(QStringLiteral("white"));
|
||||
break;
|
||||
}
|
||||
bluetoothManager->device()->currentHeart().setColor(heart->valueFontColor());
|
||||
bluetoothManager->device()->setHeartZone(currentHRZone);
|
||||
Z = QStringLiteral("Z") + QString::number(currentHRZone, 'f', 1);
|
||||
heart->setSecondLine(Z + QStringLiteral(" AVG: ") +
|
||||
@@ -4493,11 +4324,9 @@ void homeform::update() {
|
||||
#ifdef Q_OS_ANDROID
|
||||
if (settings.value(QZSettings::ant_cadence, QZSettings::default_ant_cadence).toBool() &&
|
||||
KeepAwakeHelper::antObject(false)) {
|
||||
double v = bluetoothManager->device()->currentSpeed().value();
|
||||
v *= settings.value(QZSettings::ant_speed_gain, QZSettings::default_ant_speed_gain).toDouble();
|
||||
v += settings.value(QZSettings::ant_speed_offset, QZSettings::default_ant_speed_offset).toDouble();
|
||||
KeepAwakeHelper::antObject(false)->callMethod<void>("setCadenceSpeedPower", "(FII)V", (float)v, (int)watts,
|
||||
(int)cadence);
|
||||
KeepAwakeHelper::antObject(false)->callMethod<void>(
|
||||
"setCadenceSpeedPower", "(FII)V", (float)bluetoothManager->device()->currentSpeed().value(), (int)watts,
|
||||
(int)cadence);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -4915,16 +4744,6 @@ void homeform::update() {
|
||||
}
|
||||
|
||||
if (!stopped && !paused) {
|
||||
if(settings.value(QZSettings::autolap_distance, QZSettings::default_autolap_distance).toDouble() != 0) {
|
||||
if (bluetoothManager->device()->currentDistance().lapValue() >=
|
||||
settings.value(QZSettings::autolap_distance, QZSettings::default_autolap_distance).toDouble()) {
|
||||
qDebug() << QStringLiteral("Autolap based on distance");
|
||||
Lap();
|
||||
setToastRequested("AutoLap " + QString::number(settings.value(QZSettings::autolap_distance, QZSettings::default_autolap_distance).toDouble(), 'f', 1));
|
||||
emit toastRequestedChanged(toastRequested());
|
||||
}
|
||||
}
|
||||
|
||||
if (settings.value(QZSettings::tts_enabled, QZSettings::default_tts_enabled).toBool()) {
|
||||
static double tts_speed_played = 0;
|
||||
bool description =
|
||||
@@ -5163,13 +4982,8 @@ void homeform::update() {
|
||||
}
|
||||
}
|
||||
|
||||
if(bluetoothManager->device()->currentSpeed().value() > 0 && !isinf(bluetoothManager->device()->currentSpeed().value()))
|
||||
bluetoothManager->device()->addCurrentDistance1s((bluetoothManager->device()->currentSpeed().value() / 3600.0));
|
||||
|
||||
qDebug() << "Current Distance 1s:" << bluetoothManager->device()->currentDistance1s().value() << bluetoothManager->device()->currentSpeed().value();
|
||||
|
||||
SessionLine s(
|
||||
bluetoothManager->device()->currentSpeed().value(), inclination, bluetoothManager->device()->currentDistance1s().value(),
|
||||
bluetoothManager->device()->currentSpeed().value(), inclination, bluetoothManager->device()->odometer(),
|
||||
watts, resistance, peloton_resistance, (uint8_t)bluetoothManager->device()->currentHeart().value(),
|
||||
pace, cadence, bluetoothManager->device()->calories().value(),
|
||||
bluetoothManager->device()->elevationGain().value(),
|
||||
@@ -5186,7 +5000,7 @@ void homeform::update() {
|
||||
lapTrigger = false;
|
||||
}
|
||||
|
||||
#ifndef Q_OS_IOS
|
||||
#ifdef Q_OS_ANDROID
|
||||
if (iphone_socket && iphone_socket->state() == QAbstractSocket::ConnectedState) {
|
||||
QString toSend =
|
||||
"SENDER=PAD#HR=" + QString::number(bluetoothManager->device()->currentHeart().value()) +
|
||||
@@ -5228,67 +5042,11 @@ bool homeform::getLap() {
|
||||
return true;
|
||||
}
|
||||
|
||||
QString homeform::getFileNameFromContentUri(const QString &uriString) {
|
||||
qDebug() << "getFileNameFromContentUri" << uriString;
|
||||
if(!uriString.startsWith("content")) {
|
||||
return uriString;
|
||||
}
|
||||
#ifdef Q_OS_ANDROID
|
||||
|
||||
QAndroidJniObject jUriString = QAndroidJniObject::fromString(uriString);
|
||||
QAndroidJniObject jUri = QAndroidJniObject::callStaticObjectMethod("android/net/Uri", "parse", "(Ljava/lang/String;)Landroid/net/Uri;", jUriString.object<jstring>());
|
||||
QAndroidJniObject result = QAndroidJniObject::callStaticObjectMethod(
|
||||
"org/cagnulen/qdomyoszwift/ContentHelper",
|
||||
"getFileName",
|
||||
"(Landroid/content/Context;Landroid/net/Uri;)Ljava/lang/String;",
|
||||
QtAndroid::androidContext().object(),
|
||||
jUri.object());
|
||||
return result.toString();
|
||||
#else
|
||||
return uriString;
|
||||
#endif
|
||||
}
|
||||
|
||||
QString homeform::copyAndroidContentsURI(QUrl file, QString subfolder) {
|
||||
#ifdef Q_OS_ANDROID
|
||||
QString fileNameLocal = getFileNameFromContentUri(file.toString());
|
||||
if(fileNameLocal.contains(getWritableAppDir() + subfolder + "/")) {
|
||||
qDebug() << "no need to copy file, the file is already in QZ subfolder" << file << subfolder;
|
||||
return file.toString();
|
||||
}
|
||||
QFileInfo f(fileNameLocal);
|
||||
QString filename = f.fileName();
|
||||
QFile fileFile(QQmlFile::urlToLocalFileOrQrc(file));
|
||||
QString dest = getWritableAppDir() + subfolder + "/" + filename;
|
||||
qDebug() << file.fileName() << fileNameLocal << filename;
|
||||
QFile::remove(dest);
|
||||
bool copy = fileFile.copy(dest);
|
||||
qDebug() << "copy" << dest << copy << fileFile.exists() << fileFile.isReadable();
|
||||
return dest;
|
||||
#endif
|
||||
return file.toString();
|
||||
}
|
||||
|
||||
void homeform::profile_open_clicked(const QUrl &fileName) {
|
||||
QFile file(QQmlFile::urlToLocalFileOrQrc(fileName));
|
||||
copyAndroidContentsURI(fileName, "profiles");
|
||||
}
|
||||
|
||||
void homeform::trainprogram_open_other_folder(const QUrl &fileName) {
|
||||
QFile file(QQmlFile::urlToLocalFileOrQrc(fileName));
|
||||
copyAndroidContentsURI(fileName, "training");
|
||||
}
|
||||
|
||||
void homeform::gpx_open_other_folder(const QUrl &fileName) {
|
||||
QFile file(QQmlFile::urlToLocalFileOrQrc(fileName));
|
||||
copyAndroidContentsURI(fileName, "gpx");
|
||||
}
|
||||
|
||||
void homeform::trainprogram_open_clicked(const QUrl &fileName) {
|
||||
qDebug() << QStringLiteral("trainprogram_open_clicked") << fileName;
|
||||
|
||||
QFile file(QQmlFile::urlToLocalFileOrQrc(fileName));
|
||||
|
||||
qDebug() << file.fileName();
|
||||
if (!file.fileName().isEmpty()) {
|
||||
{
|
||||
if (previewTrainProgram) {
|
||||
@@ -5299,7 +5057,7 @@ void homeform::trainprogram_open_clicked(const QUrl &fileName) {
|
||||
delete trainProgram;
|
||||
}
|
||||
|
||||
trainProgram = trainprogram::load(file.fileName(), bluetoothManager, file.fileName().right(3).toUpper());
|
||||
trainProgram = trainprogram::load(file.fileName(), bluetoothManager);
|
||||
|
||||
QString movieName = file.fileName().left(file.fileName().length() - 3) + "mp4";
|
||||
if (QFile::exists(movieName)) {
|
||||
@@ -5316,7 +5074,7 @@ void homeform::trainprogram_open_clicked(const QUrl &fileName) {
|
||||
trainingProgram()->setVideoAvailable(false);
|
||||
}
|
||||
|
||||
stravaWorkoutName = QFileInfo(file.fileName()).baseName();
|
||||
stravaWorkoutName = QFileInfo(fileName.fileName()).baseName();
|
||||
stravaPelotonInstructorName = QStringLiteral("");
|
||||
emit workoutNameChanged(workoutName());
|
||||
emit instructorNameChanged(instructorName());
|
||||
@@ -5336,15 +5094,14 @@ void homeform::trainprogram_preview(const QUrl &fileName) {
|
||||
qDebug() << QStringLiteral("trainprogram_preview") << fileName;
|
||||
|
||||
QFile file(QQmlFile::urlToLocalFileOrQrc(fileName));
|
||||
QString fileNameLocal = getFileNameFromContentUri(file.fileName());
|
||||
qDebug() << fileNameLocal;
|
||||
if (!fileNameLocal.isEmpty()) {
|
||||
qDebug() << file.fileName();
|
||||
if (!file.fileName().isEmpty()) {
|
||||
{
|
||||
if (previewTrainProgram) {
|
||||
delete previewTrainProgram;
|
||||
previewTrainProgram = 0;
|
||||
}
|
||||
previewTrainProgram = trainprogram::load(file.fileName(), bluetoothManager, fileNameLocal.right(3).toUpper());
|
||||
previewTrainProgram = trainprogram::load(file.fileName(), bluetoothManager);
|
||||
emit previewWorkoutPointsChanged(preview_workout_points());
|
||||
emit previewWorkoutDescriptionChanged(previewWorkoutDescription());
|
||||
emit previewWorkoutTagsChanged(previewWorkoutTags());
|
||||
@@ -5403,7 +5160,7 @@ void homeform::fit_save_clicked() {
|
||||
|
||||
qfit::save(filename, Session, dev->deviceType(),
|
||||
qobject_cast<m3ibike *>(dev) ? QFIT_PROCESS_DISTANCENOISE : QFIT_PROCESS_NONE,
|
||||
stravaPelotonWorkoutType, workoutName, dev->bluetoothDevice.name());
|
||||
stravaPelotonWorkoutType, workoutName);
|
||||
lastFitFileSaved = filename;
|
||||
|
||||
QSettings settings;
|
||||
@@ -5424,7 +5181,7 @@ void homeform::gpx_open_clicked(const QUrl &fileName) {
|
||||
qDebug() << QStringLiteral("gpx_open_clicked") << fileName;
|
||||
|
||||
QFile file(QQmlFile::urlToLocalFileOrQrc(fileName));
|
||||
|
||||
qDebug() << file.fileName();
|
||||
stravaWorkoutName = QFileInfo(file.fileName()).baseName();
|
||||
if (!file.fileName().isEmpty()) {
|
||||
{
|
||||
@@ -5436,7 +5193,7 @@ void homeform::gpx_open_clicked(const QUrl &fileName) {
|
||||
// KML to GPX https://www.gpsvisualizer.com/elevation
|
||||
gpx g;
|
||||
QList<trainrow> list;
|
||||
auto g_list = g.open(file.fileName(), bluetoothManager->device() ? bluetoothManager->device()->deviceType() : bluetoothdevice::BIKE);
|
||||
auto g_list = g.open(file.fileName());
|
||||
if (bluetoothManager->device())
|
||||
bluetoothManager->device()->setGPXFile(file.fileName());
|
||||
gpx_altitude_point_for_treadmill last;
|
||||
@@ -5506,7 +5263,7 @@ void homeform::gpxpreview_open_clicked(const QUrl &fileName) {
|
||||
|
||||
if (!file.fileName().isEmpty()) {
|
||||
gpx g;
|
||||
auto g_list = g.open(file.fileName(), bluetoothManager->device() ? bluetoothManager->device()->deviceType() : bluetoothdevice::BIKE);
|
||||
auto g_list = g.open(file.fileName());
|
||||
gpx_preview.clearPath();
|
||||
for (const auto &p : g_list) {
|
||||
gpx_preview.addCoordinate(QGeoCoordinate(p.latitude, p.longitude, p.elevation));
|
||||
@@ -5669,10 +5426,6 @@ bool homeform::strava_upload_file(const QByteArray &data, const QString &remoten
|
||||
activityNamePart.setHeader(QNetworkRequest::ContentDispositionHeader,
|
||||
QVariant(QStringLiteral("form-data; name=\"name\"")));
|
||||
|
||||
QString prefix = QStringLiteral("");
|
||||
if (settings.value(QZSettings::strava_date_prefix, QZSettings::default_strava_date_prefix).toBool())
|
||||
prefix = " " + QDate::currentDate().toString(Qt::TextDate);
|
||||
|
||||
// use metadata config if the user selected it
|
||||
QString activityName =
|
||||
QStringLiteral(" ") + settings.value(QZSettings::strava_suffix, QZSettings::default_strava_suffix).toString();
|
||||
@@ -5685,11 +5438,11 @@ bool homeform::strava_upload_file(const QByteArray &data, const QString &remoten
|
||||
pelotonHandler->current_ride_id;
|
||||
} else {
|
||||
if (bluetoothManager->device()->deviceType() == bluetoothdevice::TREADMILL) {
|
||||
activityName = prefix + QStringLiteral("Run") + activityName;
|
||||
activityName = QStringLiteral("Run") + activityName;
|
||||
} else if (bluetoothManager->device()->deviceType() == bluetoothdevice::ROWING) {
|
||||
activityName = prefix + QStringLiteral("Row") + activityName;
|
||||
activityName = QStringLiteral("Row") + activityName;
|
||||
} else {
|
||||
activityName = prefix + QStringLiteral("Ride") + activityName;
|
||||
activityName = QStringLiteral("Ride") + activityName;
|
||||
}
|
||||
}
|
||||
activityNamePart.setHeader(QNetworkRequest::ContentTypeHeader,
|
||||
@@ -5931,7 +5684,7 @@ QOAuth2AuthorizationCodeFlow *homeform::strava_connect() {
|
||||
#elif defined(WIN32)
|
||||
#pragma message("DEFINE STRAVA_SECRET_KEY!!!")
|
||||
#else
|
||||
#pragma message "DEFINE STRAVA_SECRET_KEY!!!"
|
||||
#warning "DEFINE STRAVA_SECRET_KEY!!!"
|
||||
#endif
|
||||
strava->setModifyParametersFunction(
|
||||
buildModifyParametersFunction(QUrl(QLatin1String("")), QUrl(QLatin1String(""))));
|
||||
@@ -5988,14 +5741,6 @@ void homeform::setVideoIconVisible(bool value) {
|
||||
emit videoIconVisibleChanged(m_VideoIconVisible);
|
||||
}
|
||||
|
||||
bool homeform::chartIconVisible() { return m_ChartIconVisible; }
|
||||
|
||||
void homeform::setChartIconVisible(bool value) {
|
||||
|
||||
m_ChartIconVisible = value;
|
||||
emit chartIconVisibleChanged(m_ChartIconVisible);
|
||||
}
|
||||
|
||||
int homeform::videoPosition() { return m_VideoPosition; }
|
||||
|
||||
void homeform::setVideoPosition(int value) {
|
||||
@@ -6052,7 +5797,7 @@ void homeform::sendMail() {
|
||||
SmtpClient smtp(STRINGIFY(SMTP_SERVER), 587, SmtpClient::TlsConnection);
|
||||
connect(&smtp, SIGNAL(smtpError(SmtpClient::SmtpError)), this, SLOT(smtpError(SmtpClient::SmtpError)));
|
||||
#else
|
||||
#pragma message "stmp server is unset!"
|
||||
#warning "stmp server is unset!"
|
||||
SmtpClient smtp(QLatin1String(""), 25, SmtpClient::TlsConnection);
|
||||
return;
|
||||
#endif
|
||||
@@ -6064,7 +5809,7 @@ void homeform::sendMail() {
|
||||
#define STRINGIFY(x) _STR(x)
|
||||
smtp.setUser(STRINGIFY(SMTP_USERNAME));
|
||||
#else
|
||||
#pragma message "smtp username is unset!"
|
||||
#warning "smtp username is unset!"
|
||||
return;
|
||||
#endif
|
||||
#ifdef SMTP_PASSWORD
|
||||
@@ -6072,7 +5817,7 @@ void homeform::sendMail() {
|
||||
#define STRINGIFY(x) _STR(x)
|
||||
smtp.setPassword(STRINGIFY(SMTP_PASSWORD));
|
||||
#else
|
||||
#pragma message "smtp password is unset!"
|
||||
#warning "smtp password is unset!"
|
||||
return;
|
||||
#endif
|
||||
|
||||
@@ -6146,30 +5891,8 @@ void homeform::sendMail() {
|
||||
QStringLiteral("Moving Time: ") + bluetoothManager->device()->movingTime().toString() + QStringLiteral("\n");
|
||||
textMessage += QStringLiteral("Weight Loss (") + weightLossUnit + "): " + QString::number(WeightLoss, 'f', 2) +
|
||||
QStringLiteral("\n");
|
||||
textMessage += QStringLiteral("Estimated VO2Max: ") + QString::number(metric::calculateVO2Max(&Session), 'f', 0) +
|
||||
textMessage += QStringLiteral("Estimated VO2Max: ") + QString::number(metric::calculateVO2Max(&Session), 'f', 1) +
|
||||
QStringLiteral("\n");
|
||||
double peak = metric::powerPeak(&Session, 5);
|
||||
double weightKg = settings.value(QZSettings::weight, QZSettings::default_weight).toFloat();
|
||||
textMessage += QStringLiteral("5 Seconds Power: ") + QString::number(peak, 'f', 0) +
|
||||
QStringLiteral("W ") + QString::number(peak/weightKg, 'f', 1) + QStringLiteral("W/Kg\n");
|
||||
peak = metric::powerPeak(&Session, 60);
|
||||
textMessage += QStringLiteral("1 Minute Power: ") + QString::number(peak, 'f', 0) +
|
||||
QStringLiteral("W ") + QString::number(peak/weightKg, 'f', 1) + QStringLiteral("W/Kg\n");
|
||||
peak = metric::powerPeak(&Session, 5 * 60);
|
||||
textMessage += QStringLiteral("5 Minutes Power: ") + QString::number(peak, 'f', 0) +
|
||||
QStringLiteral("W ") + QString::number(peak/weightKg, 'f', 1) + QStringLiteral("W/Kg\n");
|
||||
|
||||
// FTP
|
||||
double ftpSetting = settings.value(QZSettings::ftp, QZSettings::default_ftp).toDouble();
|
||||
peak = (metric::powerPeak(&Session, 20 * 60) * 0.95) * 0.95;
|
||||
textMessage += QStringLiteral("Estimated FTP: ") + QString::number(peak, 'f', 0) +
|
||||
QStringLiteral("W ");
|
||||
if(peak > ftpSetting) {
|
||||
textMessage += QStringLiteral(" FTP IMPROVED +") + QString::number(peak - ftpSetting, 'f', 0) +
|
||||
QStringLiteral("W!");
|
||||
}
|
||||
textMessage += QStringLiteral("\n");
|
||||
|
||||
if (bluetoothManager->device()->deviceType() == bluetoothdevice::BIKE) {
|
||||
textMessage += QStringLiteral("Average Cadence: ") +
|
||||
QString::number(((bike *)bluetoothManager->device())->currentCadence().average(), 'f', 0) +
|
||||
@@ -6238,10 +5961,6 @@ void homeform::sendMail() {
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef SMTP_SERVER
|
||||
textMessage += QStringLiteral("\n\nSMTP server: ") + QString(STRINGIFY(SMTP_SERVER));
|
||||
#endif
|
||||
|
||||
text.setText(textMessage);
|
||||
message.addPart(&text);
|
||||
|
||||
@@ -6422,14 +6141,10 @@ void homeform::saveSettings(const QUrl &filename) {
|
||||
}
|
||||
|
||||
void homeform::loadSettings(const QUrl &filename) {
|
||||
|
||||
QFile file(QQmlFile::urlToLocalFileOrQrc(filename));
|
||||
copyAndroidContentsURI(filename, "settings");
|
||||
|
||||
qDebug() << "homeform::loadSettings" << file.fileName();
|
||||
qDebug() << "homeform::loadSettings" << filename;
|
||||
|
||||
QSettings settings;
|
||||
QSettings settings2Load(file.fileName(), QSettings::IniFormat);
|
||||
QSettings settings2Load(filename.toLocalFile(), QSettings::IniFormat);
|
||||
auto settings2LoadAllKeys = settings2Load.allKeys();
|
||||
for (const QString &s : qAsConst(settings2LoadAllKeys)) {
|
||||
if (!s.contains(QZSettings::cryptoKeySettingsProfiles)) {
|
||||
|
||||
173
src/homeform.h
173
src/homeform.h
@@ -6,9 +6,6 @@
|
||||
#include "fit_profile.hpp"
|
||||
#include "gpx.h"
|
||||
#include "peloton.h"
|
||||
#include "qmdnsengine/browser.h"
|
||||
#include "qmdnsengine/cache.h"
|
||||
#include "qmdnsengine/resolver.h"
|
||||
#include "screencapture.h"
|
||||
#include "sessionline.h"
|
||||
#include "smtpclient/src/SmtpMime"
|
||||
@@ -23,17 +20,9 @@
|
||||
#include <QQuickItem>
|
||||
#include <QQuickItemGrabResult>
|
||||
#include <QTextToSpeech>
|
||||
|
||||
#if __has_include("secret.h")
|
||||
#include "secret.h"
|
||||
#else
|
||||
#define STRAVA_SECRET_KEY test
|
||||
#if defined(WIN32)
|
||||
#pragma message("DEFINE STRAVA_SECRET_KEY!!!")
|
||||
#else
|
||||
#warning "DEFINE STRAVA_SECRET_KEY!!!"
|
||||
#endif
|
||||
#endif
|
||||
#include "qmdnsengine/browser.h"
|
||||
#include "qmdnsengine/cache.h"
|
||||
#include "qmdnsengine/resolver.h"
|
||||
|
||||
class DataObject : public QObject {
|
||||
|
||||
@@ -148,9 +137,6 @@ class homeform : public QObject {
|
||||
Q_PROPERTY(bool mapsVisible READ mapsVisible NOTIFY mapsVisibleChanged WRITE setMapsVisible)
|
||||
Q_PROPERTY(bool videoIconVisible READ videoIconVisible NOTIFY videoIconVisibleChanged WRITE setVideoIconVisible)
|
||||
Q_PROPERTY(bool videoVisible READ videoVisible NOTIFY videoVisibleChanged WRITE setVideoVisible)
|
||||
Q_PROPERTY(bool chartIconVisible READ chartIconVisible NOTIFY chartIconVisibleChanged WRITE setChartIconVisible)
|
||||
Q_PROPERTY(
|
||||
bool chartFooterVisible READ chartFooterVisible NOTIFY chartFooterVisibleChanged WRITE setChartFooterVisible)
|
||||
Q_PROPERTY(QUrl videoPath READ videoPath NOTIFY videoPathChanged)
|
||||
Q_PROPERTY(int videoPosition READ videoPosition NOTIFY videoPositionChanged WRITE setVideoPosition)
|
||||
Q_PROPERTY(double videoRate READ videoRate NOTIFY videoRateChanged WRITE setVideoRate)
|
||||
@@ -199,7 +185,6 @@ class homeform : public QObject {
|
||||
QObject *stack = rootObject;
|
||||
screenCapture s(reinterpret_cast<QQuickView *>(stack));
|
||||
s.capture(filenameScreenshot);
|
||||
chartImagesFilenames.append(filenameScreenshot);
|
||||
}
|
||||
|
||||
Q_INVOKABLE void save_screenshot_chart(QQuickItem *item, QString filename) {
|
||||
@@ -399,8 +384,6 @@ class homeform : public QObject {
|
||||
bool mapsVisible();
|
||||
bool videoIconVisible();
|
||||
bool videoVisible() { return m_VideoVisible; }
|
||||
bool chartIconVisible();
|
||||
bool chartFooterVisible() { return m_ChartFooterVisible; }
|
||||
int videoPosition();
|
||||
double videoRate();
|
||||
double currentSpeed() {
|
||||
@@ -432,15 +415,10 @@ class homeform : public QObject {
|
||||
}
|
||||
void setLicensePopupVisible(bool value);
|
||||
void setVideoIconVisible(bool value);
|
||||
void setChartIconVisible(bool value);
|
||||
void setVideoVisible(bool value) {
|
||||
m_VideoVisible = value;
|
||||
emit videoVisibleChanged(m_VideoVisible);
|
||||
}
|
||||
void setChartFooterVisible(bool value) {
|
||||
m_ChartFooterVisible = value;
|
||||
emit chartFooterVisibleChanged(m_ChartFooterVisible);
|
||||
}
|
||||
void setVideoPosition(int position); // on startup
|
||||
void videoSeekPosition(int ms); // in realtime
|
||||
void setVideoRate(double rate);
|
||||
@@ -550,12 +528,73 @@ class homeform : public QObject {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool trainProgramLoadedWithVideo() { return (trainProgram && trainProgram->videoAvailable); }
|
||||
bool trainProgramLoadedWithVideo() {
|
||||
return (trainProgram && trainProgram->videoAvailable);
|
||||
}
|
||||
|
||||
QString getStravaAuthUrl() { return stravaAuthUrl; }
|
||||
bool stravaWebVisible() { return stravaAuthWebVisible; }
|
||||
trainprogram *trainingProgram() { return trainProgram; }
|
||||
|
||||
|
||||
private:
|
||||
static homeform *m_singleton;
|
||||
TemplateInfoSenderBuilder *userTemplateManager = nullptr;
|
||||
TemplateInfoSenderBuilder *innerTemplateManager = nullptr;
|
||||
QList<QObject *> dataList;
|
||||
QList<SessionLine> Session;
|
||||
bluetooth *bluetoothManager;
|
||||
QQmlApplicationEngine *engine;
|
||||
trainprogram *trainProgram = nullptr;
|
||||
trainprogram *previewTrainProgram = nullptr;
|
||||
QString backupFitFileName =
|
||||
QStringLiteral("QZ-backup-") +
|
||||
QDateTime::currentDateTime().toString().replace(QStringLiteral(":"), QStringLiteral("_")) +
|
||||
QStringLiteral(".fit");
|
||||
|
||||
int m_topBarHeight = 120;
|
||||
QString m_info = QStringLiteral("Connecting...");
|
||||
bool m_labelHelp = true;
|
||||
bool m_generalPopupVisible = false;
|
||||
bool m_LicensePopupVisible = false;
|
||||
bool m_MapsVisible = false;
|
||||
bool m_VideoIconVisible = false;
|
||||
bool m_VideoVisible = false;
|
||||
int m_VideoPosition = 0;
|
||||
double m_VideoRate = 1;
|
||||
QOAuth2AuthorizationCodeFlow *strava = nullptr;
|
||||
QNetworkAccessManager *manager = nullptr;
|
||||
QOAuthHttpServerReplyHandler *stravaReplyHandler = nullptr;
|
||||
|
||||
bool paused = false;
|
||||
bool stopped = false;
|
||||
bool lapTrigger = false;
|
||||
|
||||
peloton *pelotonHandler = nullptr;
|
||||
bool m_pelotonAskStart = false;
|
||||
QString m_pelotonProvider = "";
|
||||
QString m_toastRequested = "";
|
||||
int m_pelotonLoginState = -1;
|
||||
int m_pzpLoginState = -1;
|
||||
QString stravaPelotonActivityName;
|
||||
QString stravaPelotonInstructorName;
|
||||
QString stravaWorkoutName = "";
|
||||
QUrl movieFileName;
|
||||
FIT_SPORT stravaPelotonWorkoutType = FIT_SPORT_INVALID;
|
||||
QString activityDescription;
|
||||
QString pelotonAskedName = QStringLiteral("");
|
||||
QString pelotonAskedInstructor = QStringLiteral("");
|
||||
QString pelotonAbortedName = QStringLiteral("");
|
||||
QString pelotonAbortedInstructor = QStringLiteral("");
|
||||
|
||||
QString lastFitFileSaved = QLatin1String("");
|
||||
QString lastTrainProgramFileSaved = QLatin1String("");
|
||||
|
||||
QList<QString> chartImagesFilenames;
|
||||
|
||||
bool m_autoresistance = true;
|
||||
bool m_stopRequested = false;
|
||||
bool m_startRequested = false;
|
||||
|
||||
DataObject *speed;
|
||||
DataObject *inclination;
|
||||
DataObject *cadence;
|
||||
@@ -618,68 +657,6 @@ class homeform : public QObject {
|
||||
DataObject *preset_inclination_5;
|
||||
DataObject *pace_last500m;
|
||||
|
||||
private:
|
||||
static homeform *m_singleton;
|
||||
TemplateInfoSenderBuilder *userTemplateManager = nullptr;
|
||||
TemplateInfoSenderBuilder *innerTemplateManager = nullptr;
|
||||
QList<QObject *> dataList;
|
||||
QList<SessionLine> Session;
|
||||
bluetooth *bluetoothManager;
|
||||
QQmlApplicationEngine *engine;
|
||||
trainprogram *trainProgram = nullptr;
|
||||
trainprogram *previewTrainProgram = nullptr;
|
||||
QString backupFitFileName =
|
||||
QStringLiteral("QZ-backup-") +
|
||||
QDateTime::currentDateTime().toString().replace(QStringLiteral(":"), QStringLiteral("_")) +
|
||||
QStringLiteral(".fit");
|
||||
|
||||
int m_topBarHeight = 120;
|
||||
QString m_info = QStringLiteral("Connecting...");
|
||||
bool m_labelHelp = true;
|
||||
bool m_generalPopupVisible = false;
|
||||
bool m_LicensePopupVisible = false;
|
||||
bool m_MapsVisible = false;
|
||||
bool m_VideoIconVisible = false;
|
||||
bool m_VideoVisible = false;
|
||||
bool m_ChartFooterVisible = false;
|
||||
bool m_ChartIconVisible = false;
|
||||
int m_VideoPosition = 0;
|
||||
double m_VideoRate = 1;
|
||||
QOAuth2AuthorizationCodeFlow *strava = nullptr;
|
||||
QNetworkAccessManager *manager = nullptr;
|
||||
QOAuthHttpServerReplyHandler *stravaReplyHandler = nullptr;
|
||||
|
||||
bool paused = false;
|
||||
bool stopped = false;
|
||||
bool lapTrigger = false;
|
||||
|
||||
peloton *pelotonHandler = nullptr;
|
||||
bool m_pelotonAskStart = false;
|
||||
QString m_pelotonProvider = "";
|
||||
QString m_toastRequested = "";
|
||||
int m_pelotonLoginState = -1;
|
||||
int m_pzpLoginState = -1;
|
||||
QString stravaPelotonActivityName;
|
||||
QString stravaPelotonInstructorName;
|
||||
QString stravaWorkoutName = "";
|
||||
QUrl movieFileName;
|
||||
FIT_SPORT stravaPelotonWorkoutType = FIT_SPORT_INVALID;
|
||||
QString activityDescription;
|
||||
QString pelotonAskedName = QStringLiteral("");
|
||||
QString pelotonAskedInstructor = QStringLiteral("");
|
||||
QString pelotonAbortedName = QStringLiteral("");
|
||||
QString pelotonAbortedInstructor = QStringLiteral("");
|
||||
|
||||
QString lastFitFileSaved = QLatin1String("");
|
||||
QString lastTrainProgramFileSaved = QLatin1String("");
|
||||
|
||||
QList<QString> chartImagesFilenames;
|
||||
|
||||
bool m_autoresistance = true;
|
||||
bool m_stopRequested = false;
|
||||
bool m_startRequested = false;
|
||||
bool m_overridePower = false;
|
||||
|
||||
QTimer *timer;
|
||||
QTimer *backupTimer;
|
||||
|
||||
@@ -695,9 +672,6 @@ class homeform : public QObject {
|
||||
|
||||
static quint64 cryptoKeySettingsProfiles();
|
||||
|
||||
static QString copyAndroidContentsURI(QUrl file, QString subfolder);
|
||||
static QString getFileNameFromContentUri(const QString &uriString);
|
||||
|
||||
int16_t fanOverride = 0;
|
||||
|
||||
void update();
|
||||
@@ -722,17 +696,15 @@ class homeform : public QObject {
|
||||
|
||||
#ifdef Q_OS_ANDROID
|
||||
bool floating_open = false;
|
||||
#endif
|
||||
|
||||
#ifndef Q_OS_IOS
|
||||
QMdnsEngine::Browser *iphone_browser = nullptr;
|
||||
QMdnsEngine::Resolver *iphone_resolver = nullptr;
|
||||
QMdnsEngine::Browser* iphone_browser = nullptr;
|
||||
QMdnsEngine::Resolver* iphone_resolver = nullptr;
|
||||
QMdnsEngine::Server iphone_server;
|
||||
QMdnsEngine::Cache iphone_cache;
|
||||
QTcpSocket *iphone_socket = nullptr;
|
||||
QTcpSocket* iphone_socket = nullptr;
|
||||
QMdnsEngine::Service iphone_service;
|
||||
QHostAddress iphone_address;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
public slots:
|
||||
void aboutToQuit();
|
||||
@@ -762,9 +734,6 @@ class homeform : public QObject {
|
||||
void deviceConnected(QBluetoothDeviceInfo b);
|
||||
void ftmsAccessoryConnected(smartspin2k *d);
|
||||
void trainprogram_open_clicked(const QUrl &fileName);
|
||||
void trainprogram_open_other_folder(const QUrl &fileName);
|
||||
void gpx_open_other_folder(const QUrl &fileName);
|
||||
void profile_open_clicked(const QUrl &fileName);
|
||||
void trainprogram_preview(const QUrl &fileName);
|
||||
void gpxpreview_open_clicked(const QUrl &fileName);
|
||||
void trainprogram_zwo_loaded(const QString &comp);
|
||||
@@ -835,8 +804,6 @@ class homeform : public QObject {
|
||||
void videoPositionChanged(int value);
|
||||
void videoPathChanged(QUrl value);
|
||||
void videoRateChanged(double value);
|
||||
void chartIconVisibleChanged(bool value);
|
||||
void chartFooterVisibleChanged(bool value);
|
||||
void currentSpeedChanged(double value);
|
||||
void mapsVisibleChanged(bool value);
|
||||
void autoResistanceChanged(bool value);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user