Compare commits

..

7 Commits

Author SHA1 Message Date
Roberto Viola
04d37e0a68 Merge remote-tracking branch 'origin/master' into fixing_trainprogram_jitter 2025-02-23 16:30:47 +00:00
Roberto Viola
b5890ea818 Update trainprogram.cpp 2025-02-12 11:24:12 +01:00
Roberto Viola
83627f5397 Merge branch 'master' into fixing_trainprogram_jitter 2025-02-12 10:07:42 +01:00
Roberto Viola
2b8af5d777 Update trainprogram.cpp 2025-02-09 09:39:52 +01:00
Roberto Viola
3f6b284468 Merge branch 'master' into fixing_trainprogram_jitter 2025-01-30 10:05:48 +01:00
Roberto Viola
1be9e2620d Update trainprogram.cpp 2023-12-01 15:08:14 +01:00
Roberto Viola
805981df4d fixing 2023-12-01 14:53:33 +01:00
33 changed files with 285 additions and 1996 deletions

View File

@@ -89,7 +89,7 @@ jobs:
- uses: msys2/setup-msys2@v2
with:
install: mingw-w64-x86_64-toolchain mingw-w64-x86_64-qt5-webview mingw-w64-x86_64-protobuf mingw-w64-x86_64-abseil-cpp
install: mingw-w64-x86_64-toolchain mingw-w64-x86_64-qt5-webview
msystem: mingw64
release: false
@@ -128,7 +128,7 @@ jobs:
run: |
cd src
echo "#define STRAVA_SECRET_KEY ${{ secrets.strava_secret_key }}" > secret.h
echo "#define PELOTON_SECRET_KEY ${{ secrets.peloton_secret_key }}" >> secret.h
echo "#define PELOTON_SECRET_KEY ${{ secrets.peloton_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
@@ -137,10 +137,6 @@ jobs:
- name: Build
run: |
#cp "C:/mingw64/bin/libabsl*.*" .
#cp "C:/mingw64/lib/libabsl*.*" .
#cp "C:/mingw64/bin/libproto*.*" .
#cp "C:/mingw64/lib/libproto*.*" .
qmake
make -j8
cd src/debug
@@ -152,11 +148,6 @@ jobs:
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:/mingw64/bin/zlib1.dll" .
cp "C:/mingw64/bin/libabsl*.*" .
cp "C:/mingw64/lib/libabsl*.*" .
cp "C:/mingw64/bin/libproto*.*" .
cp "C:/mingw64/lib/libproto*.*" .
cp ../../../icons/iOS/iTunesArtwork@2x.png .
cp ../../AppxManifest.xml .
cp ../../windows/*.py .
@@ -173,10 +164,6 @@ jobs:
- name: Build without python
run: |
#cp "C:/mingw64/bin/libabsl*.*" .
#cp "C:/mingw64/lib/libabsl*.*" .
#cp "C:/mingw64/bin/libproto*.*" .
#cp "C:/mingw64/lib/libproto*.*" .
qmake
make -j8
cd src/debug
@@ -188,11 +175,6 @@ jobs:
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:/mingw64/bin/zlib1.dll" .
cp "C:/mingw64/bin/libabsl*.*" .
cp "C:/mingw64/lib/libabsl*.*" .
cp "C:/mingw64/bin/libproto*.*" .
cp "C:/mingw64/lib/libproto*.*" .
cp ../../../icons/iOS/iTunesArtwork@2x.png .
cp ../../AppxManifest.xml .
cp ../../../windows_openssl/*.* .
@@ -323,7 +305,7 @@ jobs:
# qmake
# cd src
# echo "#define STRAVA_SECRET_KEY ${{ secrets.strava_secret_key }}" > secret.h
# echo "#define PELOTON_SECRET_KEY ${{ secrets.peloton_secret_key }}" >> secret.h
# echo "#define PELOTON_SECRET_KEY ${{ secrets.peloton_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
@@ -427,14 +409,14 @@ jobs:
path: "src/qthttpserver"
- name: Install packages required to run QZ inside workflow
run: sudo apt update -y && sudo apt-get install -y qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools qtquickcontrols2-5-dev libqt5bluetooth5 libqt5widgets5 libqt5positioning5 libqt5xml5 qtconnectivity5-dev qtpositioning5-dev libqt5charts5-dev libqt5charts5 libqt5networkauth5-dev libqt5serialbus* libqt5websockets5* libxcb-randr0-dev libxcb-xtest0-dev libxcb-xinerama0-dev libxcb-shape0-dev libxcb-xkb-dev cmake protobuf-compiler libprotobuf-dev
run: sudo apt update -y && sudo apt-get install -y qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools qtquickcontrols2-5-dev libqt5bluetooth5 libqt5widgets5 libqt5positioning5 libqt5xml5 qtconnectivity5-dev qtpositioning5-dev libqt5charts5-dev libqt5charts5 libqt5networkauth5-dev libqt5websockets5* libxcb-randr0-dev libxcb-xtest0-dev libxcb-xinerama0-dev libxcb-shape0-dev libxcb-xkb-dev
- name: Install Qt
uses: jurplel/install-qt-action@v3
with:
version: '5.15.2'
host: 'linux'
modules: 'qtnetworkauth qtcharts qtserial'
modules: 'qtnetworkauth qtcharts'
cache: 'true'
cache-key-prefix: 'install-qt-action-linux'
@@ -626,7 +608,7 @@ jobs:
export ANDROID_NDK_ROOT="${ANDROID_NDK}"
cd src
echo "#define STRAVA_SECRET_KEY ${{ secrets.strava_secret_key }}" > secret.h
echo "#define PELOTON_SECRET_KEY ${{ secrets.peloton_secret_key }}" >> secret.h
echo "#define PELOTON_SECRET_KEY ${{ secrets.peloton_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
@@ -730,7 +712,7 @@ jobs:
run: |
cd src
echo "#define STRAVA_SECRET_KEY ${{ secrets.strava_secret_key }}" > secret.h
echo "#define PELOTON_SECRET_KEY ${{ secrets.peloton_secret_key }}" >> secret.h
echo "#define PELOTON_SECRET_KEY ${{ secrets.peloton_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
@@ -841,7 +823,7 @@ jobs:
run: |
cd src
echo "#define STRAVA_SECRET_KEY ${{ secrets.strava_secret_key }}" > secret.h
echo "#define PELOTON_SECRET_KEY ${{ secrets.peloton_secret_key }}" >> secret.h
echo "#define PELOTON_SECRET_KEY ${{ secrets.peloton_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
@@ -1029,7 +1011,7 @@ jobs:
run: |
cd src
echo "#define STRAVA_SECRET_KEY ${{ secrets.strava_secret_key }}" > secret.h
echo "#define PELOTON_SECRET_KEY ${{ secrets.peloton_secret_key }}" >> secret.h
echo "#define PELOTON_SECRET_KEY ${{ secrets.peloton_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
@@ -1124,7 +1106,7 @@ jobs:
run: |
cd src
echo "#define STRAVA_SECRET_KEY ${{ secrets.strava_secret_key }}" > secret.h
echo "#define PELOTON_SECRET_KEY ${{ secrets.peloton_secret_key }}" >> secret.h
echo "#define PELOTON_SECRET_KEY ${{ secrets.peloton_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
@@ -1172,7 +1154,7 @@ jobs:
- name: Setup QEMU
uses: docker/setup-qemu-action@v3
with:
image: tonistiigi/binfmt:master
image: tonistiigi/binfmt:qemu-v7.0.0
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
@@ -1183,7 +1165,7 @@ jobs:
run: |
cd src
echo "#define STRAVA_SECRET_KEY ${{ secrets.strava_secret_key }}" > secret.h
echo "#define PELOTON_SECRET_KEY ${{ secrets.peloton_secret_key }}" >> secret.h
echo "#define PELOTON_SECRET_KEY ${{ secrets.peloton_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
@@ -1212,204 +1194,15 @@ jobs:
- name: Rename binary
run: mv src/qdomyos-zwift src/qdomyos-zwift-64bit
window-msvc2022-build:
runs-on: windows-latest
strategy:
matrix:
config:
- {python: true}
- {python: false}
steps:
- name: Checkout PR code
uses: actions/checkout@v2
with:
ref: refs/pull/1508/head
submodules: recursive
- 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: '6.8.2'
host: 'windows'
modules: 'qtnetworkauth qtcharts qtconnectivity qtspeech qtpositioning qtwebsockets qtlocation qtmultimedia'
target: "desktop"
arch: win64_msvc2022_64
dir: "${{github.workspace}}/qt/"
install-deps: "true"
cache: 'true'
cache-key-prefix: 'install-qt-action-windows'
- name: Install MSVC compiler
uses: ilammy/msvc-dev-cmd@v1
with:
# 14.1 is for vs2017, 14.2 is vs2019, following the upstream vcpkg build from Qv2ray-deps repo
#toolset: 14.2
arch: x64
# - name: download 3rd party files for qthttpserver
# run: |
# cp qHttpServerBin/5.15.2/headers/* src/qthttpserver/src/3rdparty/http-parser/
# - name: Build qthttpserver
# run: |
# cd src\qthttpserver
# qmake
# nmake
# nmake install
# cd ../..
- name: Secrets
if: github.ref == 'refs/heads/master'
run: |
cd src
echo "#define STRAVA_SECRET_KEY ${{ secrets.strava_secret_key }}" > secret.h
echo "#define PELOTON_SECRET_KEY ${{ secrets.peloton_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: Clone vcpkg
run: git clone https://github.com/microsoft/vcpkg.git
working-directory: ${{ runner.workspace }}
- name: Bootstrap vcpkg
run: .\vcpkg\bootstrap-vcpkg.bat
working-directory: ${{ runner.workspace }}
- name: Create vcpkg.json
working-directory: ${{ runner.workspace }}
run: |
echo '{
"name": "qdomyos-zwift",
"$schema": "https://raw.githubusercontent.com/microsoft/vcpkg-tool/main/docs/vcpkg.schema.json",
"dependencies": [
"protobuf",
"protobuf-c",
"abseil"
],
"builtin-baseline": "8c2fcacefba009d63672f9d137f192765e632c9f"
}' > vcpkg.json
- name: Install dependencies
run: |
.\vcpkg\vcpkg install --triplet x64-windows --x-install-root=D:\a\qdomyos-zwift\vcpkg\installed
working-directory: ${{ runner.workspace }}
- name: Build
Copy-Item -Path ${{ runner.workspace }}\vcpkg\installed\x64-windows\lib\*.* -Destination . -Verbose
Copy-Item -Path ${{ runner.workspace }}\vcpkg\installed\x64-windows\lib\*.* -Destination src/ -Verbose
Copy-Item -Path ${{ runner.workspace }}\vcpkg\installed\x64-windows\include\* -Destination src/ -Recurse -Verbose
run: |
qmake
nmake
cd src/debug
mkdir output
mkdir appx
cp qdomyos-zwift.* 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/*.* .
Copy-Item -Path ${{ runner.workspace }}\vcpkg\installed\x64-windows\bin\*.* -Destination . -Verbose
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
# Copy-Item -Path ${{ runner.workspace }}\vcpkg\installed\x64-windows\lib\*.* -Destination . -Verbose
# Copy-Item -Path ${{ runner.workspace }}\vcpkg\installed\x64-windows\lib\*.* -Destination src/ -Verbose
# Copy-Item -Path ${{ runner.workspace }}\vcpkg\installed\x64-windows\include\* -Destination src/ -Recurse -Verbose
run: |
qmake
nmake
cd src/debug
mkdir output
mkdir appx
cp qdomyos-zwift.* 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/*.* .
Copy-Item -Path ${{ runner.workspace }}\vcpkg\installed\x64-windows\bin\*.* -Destination . -Verbose
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-msvc2022-binary.zip
if: matrix.config.python
- name: Zip artifact for deployment
run: Compress-Archive src/debug/output windows-msvc2022-binary-no-python.zip
if: ${{ ! matrix.config.python }}
- name: Archive windows binary
uses: actions/upload-artifact@v4
with:
name: windows-msvc2022-binary
path: windows-msvc2022-binary.zip
if: matrix.config.python
- name: Archive windows binary
uses: actions/upload-artifact@v4
with:
name: windows-msvc2022-binary-no-python
path: windows-msvc2022-binary-no-python.zip
if: ${{ ! matrix.config.python }}
upload_to_release:
permissions: write-all
runs-on: ubuntu-20.04
if: github.event_name == 'schedule'
needs: [linux-x86-build, window-msvc2019-build, window-msvc2022-build, ios-build, window-build, android-build, raspberry-pi-build]
needs: [linux-x86-build, window-msvc2019-build, ios-build, window-build, android-build, raspberry-pi-build] # Specify the job dependencies
steps:
- name: Checkout code
uses: actions/checkout@v2
- name: Download artifacts
uses: actions/download-artifact@v4
- name: Update nightly release
uses: andelf/nightly-release@main
env:
@@ -1427,23 +1220,14 @@ jobs:
of new complex code, the stability of the program may suffer compared to
official releases, so **use it with caution**!
## Windows Builds:
- **windows-msvc2019**: Recommended for Windows 10
- **windows-msvc2022**: Recommended for Windows 11 (experimental, QT6)
- **windows**: MinGW build (alternative version)
## Other Platforms:
- **fdroid-android-trial**: Android build
- **raspberry-pi-binary**: Raspberry Pi build
__Please help us improve QZ by reporting any issues you encounter!__ :wink:
files: |
windows-msvc2019-binary-no-python/*
windows-msvc2019-binary/*
windows-msvc2022-binary-no-python/*
windows-msvc2022-binary/*
windows-msvc2019-ai-server-binary/*
windows-binary-no-python/*
windows-binary/*
fdroid-android-trial/*
raspberry-pi-binary/qdomyos-zwift-32bit
#raspberry-pi-64bit-binary/qdomyos-zwift-64bit
#2024-10-22-raspios-bookworm-arm64-lite.img.xz

View File

@@ -4255,7 +4255,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements";
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1037;
CURRENT_PROJECT_VERSION = 1035;
DEVELOPMENT_TEAM = 6335M7T29D;
ENABLE_BITCODE = NO;
GCC_PREPROCESSOR_DEFINITIONS = "ADB_HOST=1";
@@ -4449,7 +4449,7 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_ENTITLEMENTS = "../src/ios/qdomyos-zwift.entitlements";
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 1037;
CURRENT_PROJECT_VERSION = 1035;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = 6335M7T29D;
ENABLE_BITCODE = NO;
@@ -4679,7 +4679,7 @@
CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements";
CODE_SIGN_IDENTITY = "Apple Development";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1037;
CURRENT_PROJECT_VERSION = 1035;
DEVELOPMENT_TEAM = 6335M7T29D;
ENABLE_BITCODE = YES;
ENABLE_STRICT_OBJC_MSGSEND = YES;
@@ -4775,7 +4775,7 @@
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1037;
CURRENT_PROJECT_VERSION = 1035;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = 6335M7T29D;
ENABLE_BITCODE = YES;
@@ -4867,7 +4867,7 @@
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1037;
CURRENT_PROJECT_VERSION = 1035;
DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\"";
ENABLE_BITCODE = YES;
ENABLE_PREVIEWS = YES;
@@ -4983,7 +4983,7 @@
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_ENTITLEMENTS = "watchkit Extension/WatchKit Extension.entitlements";
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1037;
CURRENT_PROJECT_VERSION = 1035;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_ASSET_PATHS = "\"watchkit Extension/Preview Content\"";
ENABLE_BITCODE = YES;

View File

@@ -1,89 +0,0 @@
//#if defined(Q_OS_LINUX)
#if 1
#include "ConsoleReader.h"
#include <stdio.h>
#include <termios.h>
#include <unistd.h>
static struct termios oldSettings;
static struct termios newSettings;
/* Initialize new terminal i/o settings */
void initTermios(int echo) {
tcgetattr(0, &oldSettings); /* grab old terminal i/o settings */
newSettings = oldSettings; /* make new settings same as old settings */
newSettings.c_lflag &= ~ICANON; /* disable buffered i/o */
newSettings.c_lflag &= echo ? ECHO : ~ECHO; /* set echo mode */
tcsetattr(0, TCSANOW, &newSettings); /* use these new terminal i/o settings now */
}
/* Restore old terminal i/o settings */
void resetTermios(void) { tcsetattr(0, TCSANOW, &oldSettings); }
/* Read 1 character without echo */
char getch(void) { return getchar(); }
ConsoleReader::ConsoleReader(bluetooth *bt) {
bluetoothManager = bt;
initTermios(0);
}
ConsoleReader::~ConsoleReader() { resetTermios(); }
void ConsoleReader::run() {
forever {
char key = getch();
qDebug() << "key pressed" << key;
if (key == 'q') {
if (bluetoothManager->device() && bluetoothManager->device()->deviceType() == bluetoothdevice::TREADMILL) {
double speed = ((treadmill *)bluetoothManager->device())->currentSpeed().value();
((treadmill *)bluetoothManager->device())->changeSpeed(speed + 0.5);
}
} else if (key == 'w') {
if (bluetoothManager->device() && bluetoothManager->device()->deviceType() == bluetoothdevice::TREADMILL) {
double speed = ((treadmill *)bluetoothManager->device())->currentSpeed().value();
((treadmill *)bluetoothManager->device())->changeSpeed(speed - 0.5);
}
} else if (key == 'a') {
if (bluetoothManager->device() && bluetoothManager->device()->deviceType() == bluetoothdevice::TREADMILL) {
double inclination = ((treadmill *)bluetoothManager->device())->currentInclination().value();
((treadmill *)bluetoothManager->device())->changeInclination(inclination + 0.5, inclination + 0.5);
}
} else if (key == 's') {
if (bluetoothManager->device() && bluetoothManager->device()->deviceType() == bluetoothdevice::TREADMILL) {
double inclination = ((treadmill *)bluetoothManager->device())->currentInclination().value();
((treadmill *)bluetoothManager->device())->changeInclination(inclination - 0.5, inclination - 0.5);
}
} else if (key == '1') {
if (bluetoothManager->device() && bluetoothManager->device()->deviceType() == bluetoothdevice::TREADMILL) {
((treadmill *)bluetoothManager->device())->changeSpeed(5);
}
} else if (key == '2') {
if (bluetoothManager->device() && bluetoothManager->device()->deviceType() == bluetoothdevice::TREADMILL) {
double inclination = ((treadmill *)bluetoothManager->device())->currentInclination().value();
((treadmill *)bluetoothManager->device())->changeInclination(inclination + 0.5, inclination + 0.5);
}
} else if (key == '3') {
if (bluetoothManager->device() && bluetoothManager->device()->deviceType() == bluetoothdevice::TREADMILL) {
((treadmill *)bluetoothManager->device())->changeSpeed(10);
}
} else if (key == '4') {
if (bluetoothManager->device() && bluetoothManager->device()->deviceType() == bluetoothdevice::TREADMILL) {
double speed = ((treadmill *)bluetoothManager->device())->currentSpeed().value();
((treadmill *)bluetoothManager->device())->changeSpeed(speed - 0.5);
}
} else if (key == '5') {
if (bluetoothManager->device() && bluetoothManager->device()->deviceType() == bluetoothdevice::TREADMILL) {
double inclination = ((treadmill *)bluetoothManager->device())->currentInclination().value();
((treadmill *)bluetoothManager->device())->changeInclination(inclination - 0.5, inclination - 0.5);
}
} else if (key == '6') {
if (bluetoothManager->device() && bluetoothManager->device()->deviceType() == bluetoothdevice::TREADMILL) {
double speed = ((treadmill *)bluetoothManager->device())->currentSpeed().value();
((treadmill *)bluetoothManager->device())->changeSpeed(speed + 0.5);
}
}
emit KeyPressed(key);
}
}
#endif

View File

@@ -1,21 +0,0 @@
#ifndef CONSOLEREADER_H
#define CONSOLEREADER_H
#include "bluetooth.h"
#include <QThread>
class ConsoleReader : public QThread {
Q_OBJECT
signals:
void KeyPressed(char ch);
public:
ConsoleReader(bluetooth *bt);
~ConsoleReader();
void run();
private:
bluetooth *bluetoothManager;
};
#endif /* CONSOLEREADER_H */

View File

@@ -23,13 +23,6 @@ HomeForm {
signal plus_clicked(string name)
signal minus_clicked(string name)
signal largeButton_clicked(string name)
signal keyPressed(int key)
Keys.onPressed: (event)=> {
console.log("Keys.onPressed " + event.key)
// Emit a signal with the pressed key
keyPressed(event.key)
}
Settings {
id: settings

View File

@@ -9,15 +9,11 @@ import QtQuick.Layouts 1.3
import QtWebView 1.1
Item {
id: pelotonAuthPage
anchors.fill: parent
height: parent.height
width: parent.width
visible: true
// Signal to notify the parent stack when we want to go back
signal goBack()
WebView {
anchors.fill: parent
height: parent.height
@@ -31,11 +27,7 @@ Item {
parent: Overlay.overlay
enabled: rootItem.pelotonPopupVisible
onEnabledChanged: { if(rootItem.pelotonPopupVisible) popupPelotonConnectedWeb.open() }
onClosed: {
rootItem.pelotonPopupVisible = false;
// Attempt to go back to the previous view after the popup is closed
goBack();
}
onClosed: { rootItem.pelotonPopupVisible = false; }
x: Math.round((parent.width - width) / 2)
y: Math.round((parent.height - height) / 2)
@@ -53,7 +45,6 @@ Item {
{
NumberAnimation { property: "opacity"; from: 1.0; to: 0.0 }
}
Column {
anchors.horizontalCenter: parent.horizontalCenter
Label {
@@ -63,18 +54,5 @@ Item {
text: qsTr("Your Peloton account is now connected!<br><br>Restart the app to apply this!")
}
}
// Add a MouseArea to capture clicks anywhere on the popup
MouseArea {
anchors.fill: parent
onClicked: {
popupPelotonConnectedWeb.close();
}
}
}
// Component is being completed
Component.onCompleted: {
console.log("WebPelotonAuth loaded")
}
}

View File

@@ -5,7 +5,6 @@ import Qt.labs.settings 1.0
Page {
id: wizardPage
objectName: "wizardPage"
property int currentStep: 0
property var selectedOptions: ({})
@@ -336,7 +335,7 @@ Page {
Text {
Layout.alignment: Qt.AlignHCenter
text: qsTr("Connect to Peloton")
text: qsTr("Peloton Login")
font.pixelSize: 24
font.bold: true
color: "white"
@@ -344,38 +343,56 @@ Page {
Text {
Layout.alignment: Qt.AlignHCenter
text: qsTr("Click the button below to connect your Peloton account")
text: qsTr("Username")
font.pixelSize: 20
wrapMode: Text.WordWrap
Layout.fillWidth: true
width: stackViewLocal.width * 0.8
horizontalAlignment: Text.AlignHCenter
font.bold: true
color: "white"
}
Image {
TextField {
id: pelotonUsernameTextField
text: settings.peloton_username
horizontalAlignment: Text.AlignHCenter
Layout.alignment: Qt.AlignHCenter
source: "icons/icons/Button_Connect_Rect_DarkMode.png"
fillMode: Image.PreserveAspectFit
width: parent.width * 0.8
Layout.fillHeight: false
onAccepted: settings.peloton_username = text
onActiveFocusChanged: if(this.focus) this.cursorPosition = this.text.length
}
MouseArea {
anchors.fill: parent
onClicked: {
stackViewLocal.push("WebPelotonAuth.qml")
stackViewLocal.currentItem.goBack.connect(function() {
stackViewLocal.pop();
stackViewLocal.push(pelotonDifficultyComponent)
})
peloton_connect_clicked()
}
}
Text {
Layout.alignment: Qt.AlignHCenter
text: qsTr("Password")
font.pixelSize: 20
font.bold: true
color: "white"
}
TextField {
id: pelotonPasswordTextField
text: settings.peloton_password
horizontalAlignment: Text.AlignHCenter
Layout.fillHeight: false
Layout.alignment: Qt.AlignHCenter
inputMethodHints: Qt.ImhHiddenText
echoMode: TextInput.PasswordEchoOnEdit
onAccepted: settings.peloton_password = text
onActiveFocusChanged: if(this.focus) this.cursorPosition = this.text.length
}
Item {
Layout.preferredHeight: 50
}
WizardButton {
Layout.alignment: Qt.AlignHCenter
text: qsTr("Next")
onClicked: {
settings.peloton_username = pelotonUsernameTextField.text;
settings.peloton_password = pelotonPasswordTextField.text;
stackViewLocal.push(pelotonDifficultyComponent)
}
}
WizardButton {
Layout.alignment: Qt.AlignHCenter
text: qsTr("Back")

View File

@@ -1,5 +1,5 @@
<?xml version="1.0"?>
<manifest package="org.cagnulen.qdomyoszwift" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:versionName="2.18.22" android:versionCode="1045" 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.18.20" android:versionCode="1020" 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 -->

View File

@@ -112,7 +112,6 @@ void bluetooth::finished() {
QString nordictrack_2950_ip =
settings.value(QZSettings::nordictrack_2950_ip, QZSettings::default_nordictrack_2950_ip).toString();
QString tdf_10_ip = settings.value(QZSettings::tdf_10_ip, QZSettings::default_tdf_10_ip).toString();
bool gpio_treadmill = settings.value(QStringLiteral("gpio_treadmill"), false).toBool();
QString proform_elliptical_ip = settings.value(QZSettings::proform_elliptical_ip, QZSettings::default_proform_elliptical_ip).toString();
bool fake_bike =
settings.value(QZSettings::applewatch_fakedevice, QZSettings::default_applewatch_fakedevice).toBool();
@@ -122,7 +121,7 @@ void bluetooth::finished() {
bool fakedevice_treadmill =
settings.value(QZSettings::fakedevice_treadmill, QZSettings::default_fakedevice_treadmill).toBool();
// wifi devices on windows
if (!nordictrack_2950_ip.isEmpty() || !tdf_10_ip.isEmpty() || fake_bike || fakedevice_elliptical || fakedevice_rower || fakedevice_treadmill || !proform_elliptical_ip.isEmpty() || antbike || gpio_treadmill) {
if (!nordictrack_2950_ip.isEmpty() || !tdf_10_ip.isEmpty() || fake_bike || fakedevice_elliptical || fakedevice_rower || fakedevice_treadmill || !proform_elliptical_ip.isEmpty() || antbike) {
// faking a bluetooth device
qDebug() << "faking a bluetooth device for nordictrack_2950_ip";
deviceDiscovered(QBluetoothDeviceInfo());
@@ -449,7 +448,6 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) {
powerSensorName.startsWith(QStringLiteral("Disabled")) || power_as_bike || power_as_treadmill;
bool eliteRizerFound = eliteRizerName.startsWith(QStringLiteral("Disabled"));
bool eliteSterzoSmartFound = eliteSterzoSmartName.startsWith(QStringLiteral("Disabled"));
bool gpio_treadmill = settings.value(QStringLiteral("gpio_treadmill"), false).toBool();
bool fake_bike =
settings.value(QZSettings::applewatch_fakedevice, QZSettings::default_applewatch_fakedevice).toBool();
bool fakedevice_elliptical =
@@ -684,23 +682,6 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) {
emit searchingStop();
}
this->signalBluetoothDeviceConnected(fakeBike);
#if defined(Q_OS_WIN) || (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID))
} else if (gpio_treadmill && !gpioTreadmill) {
discoveryAgent->stop();
gpioTreadmill = new gpiotreadmill(pollDeviceTime, noConsole, noHeartService, 0.8, 0);
emit deviceConnected(b);
connect(gpioTreadmill, &bluetoothdevice::connectedAndDiscovered, this,
&bluetooth::connectedAndDiscovered);
connect(gpioTreadmill, &gpiotreadmill::debug, this, &bluetooth::debug);
connect(gpioTreadmill, &gpiotreadmill::inclinationChanged, this, &bluetooth::inclinationChanged);
// connect(cscBike, SIGNAL(disconnected()), this, SLOT(restart()));
// connect(this, SIGNAL(searchingStop()), gpioTreadmill, SLOT(searchingStop())); //NOTE: Commented due
// to #358
if (!discoveryAgent->isActive()) {
emit searchingStop();
}
this->signalBluetoothDeviceConnected(gpioTreadmill);
#endif
} else if (fakedevice_elliptical && !fakeElliptical) {
this->stopDiscovery();
fakeElliptical = new fakeelliptical(noWriteResistance, noHeartService, false);
@@ -1422,7 +1403,6 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) {
b.name().toUpper().startsWith(QStringLiteral("WLT-EP-")) || // Flow elliptical
(b.name().toUpper().startsWith("SCHWINN 810")) ||
b.name().toUpper().startsWith(QStringLiteral("KS-MC")) ||
b.name().toUpper().startsWith(QStringLiteral("ANPIUS-")) ||
(b.name().toUpper().startsWith(QStringLiteral("KS-HD-Z1D"))) || // Kingsmith WalkingPad Z1
(b.name().toUpper().startsWith(QStringLiteral("NOBLEPRO CONNECT")) && deviceHasService(b, QBluetoothUuid((quint16)0x1826))) || // FTMS
(b.name().toUpper().startsWith(QStringLiteral("TT8")) && deviceHasService(b, QBluetoothUuid((quint16)0x1826))) ||
@@ -1653,7 +1633,6 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) {
(b.name().toUpper().startsWith("NEO BIKE SMART")) ||
(b.name().toUpper().startsWith("ZDRIVE")) ||
(b.name().toUpper().startsWith("TUNTURI E60-")) ||
(b.name().toUpper().startsWith("TUNTURI F40-")) ||
(b.name().toUpper().startsWith("JFBK5.0")) ||
(b.name().toUpper().startsWith("NEO 3M ")) ||
(b.name().toUpper().startsWith("JFBK7.0")) ||
@@ -1669,8 +1648,6 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) {
(b.name().toUpper().startsWith("LYDSTO")) ||
(b.name().toUpper().startsWith("CYCLO_")) ||
(b.name().toUpper().startsWith("LCR")) ||
(b.name().toUpper().startsWith("XCX-")) ||
(b.name().toUpper().startsWith("L-") && b.name().length() == 11) ||
(b.name().toUpper().startsWith(QStringLiteral("FIT-BK-"))) ||
(b.name().toUpper().startsWith("VFSPINBIKE")) ||
(b.name().toUpper().startsWith("GLT") && deviceHasService(b, QBluetoothUuid((quint16)0x1826))) ||
@@ -1813,7 +1790,6 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) {
b.name().toUpper().startsWith(QStringLiteral("I-ROWER")) ||
b.name().toUpper().startsWith(QStringLiteral("YOROTO-RW-")) ||
b.name().toUpper().startsWith(QStringLiteral("SF-RW")) ||
b.name().toUpper().startsWith(QStringLiteral("ROGUE CONSOLE ")) ||
b.name().toUpper().startsWith(QStringLiteral("DFIT-L-R")) ||
!b.name().compare(ftms_rower, Qt::CaseInsensitive) ||
(b.name().toUpper().startsWith(QStringLiteral("PM5")) &&
@@ -3243,13 +3219,6 @@ void bluetooth::restart() {
delete fakeBike;
fakeBike = nullptr;
}
#if defined(Q_OS_WIN) || (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID))
if (gpioTreadmill) {
delete gpioTreadmill;
gpioTreadmill = nullptr;
}
#endif
if (fakeElliptical) {
delete fakeElliptical;
@@ -3712,10 +3681,6 @@ bluetoothdevice *bluetooth::device() {
return powerTreadmill;
} else if (fakeBike) {
return fakeBike;
#if defined(Q_OS_WIN) || (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID))
} else if (gpioTreadmill) {
return gpioTreadmill;
#endif
} else if (fakeElliptical) {
return fakeElliptical;
} else if (fakeRower) {

View File

@@ -101,9 +101,6 @@
#include "devices/proformwifitreadmill/proformwifitreadmill.h"
#include "devices/schwinn170bike/schwinn170bike.h"
#include "devices/schwinnic4bike/schwinnic4bike.h"
#if defined(Q_OS_WIN) || (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID))
#include "gpiotreadmill.h"
#endif
#include "signalhandler.h"
#include "devices/skandikawiribike/skandikawiribike.h"
#include "devices/smartrowrower/smartrowrower.h"
@@ -210,9 +207,6 @@ class bluetooth : public QObject, public SignalHandler {
trxappgateusbelliptical *trxappgateusbElliptical = nullptr;
echelonconnectsport *echelonConnectSport = nullptr;
yesoulbike *yesoulBike = nullptr;
#if defined(Q_OS_WIN) || (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID))
gpiotreadmill *gpioTreadmill = nullptr;
#endif
flywheelbike *flywheelBike = nullptr;
nordictrackelliptical *nordictrackElliptical = nullptr;
nordictrackifitadbtreadmill *nordictrackifitadbTreadmill = nullptr;

View File

@@ -475,9 +475,9 @@ void bluetoothdevice::setGPXFile(QString filename) {
}
}
void bluetoothdevice::setHeartZone(double hz) {
void bluetoothdevice::setHeartZone(double hz) {
HeartZone = hz;
if(isPaused() == false && currentHeart().value() > 0) {
if(isPaused() == false) {
hz = hz - 1;
if(hz >= maxHeartZone() ) {
hrZonesSeconds[maxHeartZone() - 1].setValue(hrZonesSeconds[maxHeartZone() - 1].value() + 1);

View File

@@ -129,17 +129,14 @@ void ftmsbike::init() {
if (initDone)
return;
if(ICSE) {
uint8_t write[] = {FTMS_REQUEST_CONTROL};
bool ret = writeCharacteristic(write, sizeof(write), "requestControl", false, true);
write[0] = {FTMS_RESET};
ret = writeCharacteristic(write, sizeof(write), "reset", false, true);
}
uint8_t write[] = {FTMS_REQUEST_CONTROL};
bool ret = writeCharacteristic(write, sizeof(write), "requestControl", false, true);
write[0] = {FTMS_START_RESUME};
ret = writeCharacteristic(write, sizeof(write), "start simulation", false, true);
if(resistance_lvl_mode && DIRETO_XR) {
setWheelDiameter(2070.0);
} else {
write[0] = {FTMS_START_RESUME};
ret = writeCharacteristic(write, sizeof(write), "start simulation", false, true);
}
if(ret) {
initDone = true;
@@ -148,6 +145,10 @@ void ftmsbike::init() {
}
ftmsbike::~ftmsbike() {
// Set wheel circumference back to 2070 when object is destroyed
if (DIRETO_XR) {
setWheelDiameter(2070.0);
}
}
void ftmsbike::zwiftPlayInit() {
@@ -275,8 +276,6 @@ void ftmsbike::update() {
if (initRequest) {
zwiftPlayInit();
if(ICSE)
requestResistance = 1; // to force the engine to send every second a target inclination
initRequest = false;
} else if (bluetoothDevice.isValid() &&
m_control->state() == QLowEnergyController::DiscoveredState //&&
@@ -320,16 +319,24 @@ void ftmsbike::update() {
(requestPower == 0 || requestPower == -1)) {
init();
forceResistance(requestResistance + (gears() * 5));
if(DIRETO_XR && gears_zwift_ratio)
setWheelDiameter(wheelCircumference::gearsToWheelDiameter(gears()));
else {
forceResistance(requestResistance + (gears() * 5));
if(DIRETO_XR)
Resistance = requestResistance;
}
}
}
if(!ICSE)
requestResistance = -1;
requestResistance = -1;
}
if((virtualBike && virtualBike->ftmsDeviceConnected()) && lastGearValue != gears() && lastRawRequestedInclinationValue != -100 && lastPacketFromFTMS.length() >= 7) {
qDebug() << "injecting fake ftms frame in order to send the new gear value ASAP" << lastPacketFromFTMS.toHex(' ');
ftmsCharacteristicChanged(QLowEnergyCharacteristic(), lastPacketFromFTMS);
if(DIRETO_XR && gears_zwift_ratio) {
setWheelDiameter(wheelCircumference::gearsToWheelDiameter(gears()));
} else {
qDebug() << "injecting fake ftms frame in order to send the new gear value ASAP" << lastPacketFromFTMS.toHex(' ');
ftmsCharacteristicChanged(QLowEnergyCharacteristic(), lastPacketFromFTMS);
}
}
if(zwiftPlayService && gears_zwift_ratio && lastGearValue != gears()) {
@@ -948,18 +955,7 @@ void ftmsbike::stateChanged(QLowEnergyService::ServiceState state) {
qDebug() << s->serviceUuid() << QStringLiteral("connected!");
if (ICSE) {
QBluetoothUuid ftmsService((quint16)0x1826);
QBluetoothUuid CSCService((quint16)0x1816);
if (s->serviceUuid() != ftmsService && s->serviceUuid() != CSCService) {
qDebug() << QStringLiteral("ICSE bike wants to be subscribed only to FTMS and CSC services in order "
"to send metrics")
<< s->serviceUuid();
continue;
}
}
if (settings.value(QZSettings::hammer_racer_s, QZSettings::default_hammer_racer_s).toBool() || SCH_190U || DOMYOS || SMB1) {
if (settings.value(QZSettings::hammer_racer_s, QZSettings::default_hammer_racer_s).toBool() || ICSE || SCH_190U || DOMYOS || SMB1) {
QBluetoothUuid ftmsService((quint16)0x1826);
if (s->serviceUuid() != ftmsService) {
qDebug() << QStringLiteral("hammer racer bike wants to be subscribed only to FTMS service in order "
@@ -1019,7 +1015,7 @@ void ftmsbike::stateChanged(QLowEnergyService::ServiceState state) {
}
QBluetoothUuid _zwiftPlayWriteCharControlPointId(QStringLiteral("00000003-19ca-4651-86e5-fa29dcdd09d1"));
if (c.uuid() == _zwiftPlayWriteCharControlPointId) {
if (c.uuid() == _zwiftPlayWriteCharControlPointId && !DIRETO_XR) {
qDebug() << QStringLiteral("Zwift Play service and Control Point found");
zwiftPlayWriteChar = c;
zwiftPlayService = s;
@@ -1162,9 +1158,7 @@ void ftmsbike::ftmsCharacteristicChanged(const QLowEnergyCharacteristic &charact
} else if(b.at(0) == FTMS_SET_TARGET_POWER && zwiftPlayService != nullptr && gears_zwift_ratio) {
qDebug() << "discarding";
return;
}
// gears on erg mode is quite useless and it's confusing
/* else if(b.at(0) == FTMS_SET_TARGET_POWER && b.length() > 2) {
} else if(b.at(0) == FTMS_SET_TARGET_POWER && b.length() > 2) {
lastPacketFromFTMS.clear();
for(int i=0; i<b.length(); i++)
lastPacketFromFTMS.append(b.at(i));
@@ -1176,7 +1170,7 @@ void ftmsbike::ftmsCharacteristicChanged(const QLowEnergyCharacteristic &charact
b[1] = power & 0xFF;
b[2] = power >> 8;
qDebug() << "applying gears mod" << gears() << gearsZwiftRatio() << power;
}*/
}
writeCharacteristic((uint8_t*)b.data(), b.length(), "injectWrite ", false, true);
}
@@ -1385,7 +1379,7 @@ double ftmsbike::maxGears() {
QSettings settings;
bool gears_zwift_ratio = settings.value(QZSettings::gears_zwift_ratio, QZSettings::default_gears_zwift_ratio).toBool();
if((zwiftPlayService != nullptr) && gears_zwift_ratio) {
if((zwiftPlayService != nullptr || DIRETO_XR) && gears_zwift_ratio) {
wheelCircumference::GearTable g;
return g.maxGears;
} else if(WATTBIKE) {
@@ -1399,7 +1393,7 @@ double ftmsbike::minGears() {
QSettings settings;
bool gears_zwift_ratio = settings.value(QZSettings::gears_zwift_ratio, QZSettings::default_gears_zwift_ratio).toBool();
if((zwiftPlayService != nullptr) && gears_zwift_ratio ) {
if((zwiftPlayService != nullptr || DIRETO_XR) && gears_zwift_ratio ) {
return 1;
} else if(WATTBIKE) {
return 1;

View File

@@ -212,7 +212,6 @@ void nordictrackifitadbbike::processPendingDatagrams() {
uint16_t port;
bool freemotion_coachbike_b22_7 = settings.value(QZSettings::freemotion_coachbike_b22_7, QZSettings::default_freemotion_coachbike_b22_7).toBool();
while (socket->hasPendingDatagrams()) {
QDateTime now = QDateTime::currentDateTime();
QByteArray datagram;
datagram.resize(socket->pendingDatagramSize());
socket->readDatagram(datagram.data(), datagram.size(), &sender, &port);
@@ -291,7 +290,7 @@ void nordictrackifitadbbike::processPendingDatagrams() {
if (settings.value(QZSettings::speed_power_based, QZSettings::default_speed_power_based).toBool()) {
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());
}
bool proform_studio_NTEX71021 =
@@ -345,8 +344,8 @@ void nordictrackifitadbbike::processPendingDatagrams() {
qDebug() << QString::number(ret) + " >> " + message;
}
// since the motor of the bike is slow, let's filter the inclination changes to more than 4 seconds
else if (lastInclinationChanged.secsTo(now) > inclination_delay_seconds) {
lastInclinationChanged = now;
else if (lastInclinationChanged.secsTo(QDateTime::currentDateTime()) > inclination_delay_seconds) {
lastInclinationChanged = QDateTime::currentDateTime();
if (nordictrack_ifit_adb_remote) {
bool erg_mode = settings.value(QZSettings::zwift_erg, QZSettings::default_zwift_erg).toBool();
if (requestInclination != -100 && erg_mode && requestResistance != -100) {
@@ -432,18 +431,18 @@ void nordictrackifitadbbike::processPendingDatagrams() {
KCal +=
((((0.048 * ((double)watts()) + 1.19) * weight * 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
// KCal = (((uint16_t)((uint8_t)newValue.at(15)) << 8) + (uint16_t)((uint8_t) newValue.at(14)));
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())

View File

@@ -189,16 +189,25 @@ void proformbike::forceResistance(resistance_t requestResistance) {
writeCharacteristic((uint8_t *)res2, sizeof(res2), QStringLiteral("resistance2"), false, false);
writeCharacteristic((uint8_t *)res3, sizeof(res3), QStringLiteral("resistance3"), false, true);
} else if (proform_xbike) {
const uint8_t res1[] = {0xff, 0x0d, 0x02, 0x04, 0x02, 0x09, 0x07, 0x09, 0x02, 0x01, 0x04, 0x84, 0x03, 0x00, 0x9e, 0x00, 0x00, 0x00, 0x00, 0x00}; // pkt3920
const uint8_t res2[] = {0xff, 0x0d, 0x02, 0x04, 0x02, 0x09, 0x07, 0x09, 0x02, 0x01, 0x04, 0x6c, 0x07, 0x00, 0x8a, 0x00, 0x00, 0x00, 0x00, 0x00}; // pkt994
const uint8_t res3[] = {0xff, 0x0d, 0x02, 0x04, 0x02, 0x09, 0x07, 0x09, 0x02, 0x01, 0x04, 0x54, 0x0b, 0x00, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00}; // pkt1325
const uint8_t res4[] = {0xff, 0x0d, 0x02, 0x04, 0x02, 0x09, 0x07, 0x09, 0x02, 0x01, 0x04, 0x3c, 0x0f, 0x00, 0x62, 0x00, 0x00, 0x00, 0x00, 0x00}; // pkt1636
const uint8_t res5[] = {0xff, 0x0d, 0x02, 0x04, 0x02, 0x09, 0x07, 0x09, 0x02, 0x01, 0x04, 0x24, 0x13, 0x00, 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00}; // pkt1786
const uint8_t res6[] = {0xff, 0x0d, 0x02, 0x04, 0x02, 0x09, 0x07, 0x09, 0x02, 0x01, 0x04, 0x0c, 0x17, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00}; // pkt1905
const uint8_t res7[] = {0xff, 0x0d, 0x02, 0x04, 0x02, 0x09, 0x07, 0x09, 0x02, 0x01, 0x04, 0xf4, 0x1a, 0x00, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00}; // pkt2015
const uint8_t res8[] = {0xff, 0x0d, 0x02, 0x04, 0x02, 0x09, 0x07, 0x09, 0x02, 0x01, 0x04, 0xdc, 0x1e, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00}; // pkt2134
const uint8_t res9[] = {0xff, 0x0d, 0x02, 0x04, 0x02, 0x09, 0x07, 0x09, 0x02, 0x01, 0x04, 0xc4, 0x22, 0x00, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00}; // pkt2209
const uint8_t res10[] = {0xff, 0x0d, 0x02, 0x04, 0x02, 0x09, 0x07, 0x09, 0x02, 0x01, 0x04, 0xac, 0x26, 0x00, 0xe9, 0x00, 0x00, 0x00, 0x00, 0x00}; // pkt2293
const uint8_t res1[] = {0xff, 0x0d, 0x02, 0x04, 0x02, 0x09, 0x07, 0x09, 0x02, 0x01, 0x04, 0x6c, 0x07, 0x00, 0x8a, 0x00, 0x00, 0x00, 0x00, 0x00}; // pkt994
const uint8_t res2[] = {0xff, 0x0d, 0x02, 0x04, 0x02, 0x09, 0x07, 0x09, 0x02, 0x01, 0x04, 0x54, 0x0b, 0x00, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00}; // pkt1325
const uint8_t res3[] = {0xff, 0x0d, 0x02, 0x04, 0x02, 0x09, 0x07, 0x09, 0x02, 0x01, 0x04, 0x3c, 0x0f, 0x00, 0x62, 0x00, 0x00, 0x00, 0x00, 0x00}; // pkt1636
const uint8_t res4[] = {0xff, 0x0d, 0x02, 0x04, 0x02, 0x09, 0x07, 0x09, 0x02, 0x01, 0x04, 0x24, 0x13, 0x00, 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00}; // pkt1786
const uint8_t res5[] = {0xff, 0x0d, 0x02, 0x04, 0x02, 0x09, 0x07, 0x09, 0x02, 0x01, 0x04, 0x0c, 0x17, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00}; // pkt1905
const uint8_t res6[] = {0xff, 0x0d, 0x02, 0x04, 0x02, 0x09, 0x07, 0x09, 0x02, 0x01, 0x04, 0xf4, 0x1a, 0x00, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00}; // pkt2015
const uint8_t res7[] = {0xff, 0x0d, 0x02, 0x04, 0x02, 0x09, 0x07, 0x09, 0x02, 0x01, 0x04, 0xdc, 0x1e, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00}; // pkt2134
const uint8_t res8[] = {0xff, 0x0d, 0x02, 0x04, 0x02, 0x09, 0x07, 0x09, 0x02, 0x01, 0x04, 0xc4, 0x22, 0x00, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00}; // pkt2209
const uint8_t res9[] = {0xff, 0x0d, 0x02, 0x04, 0x02, 0x09, 0x07, 0x09, 0x02, 0x01, 0x04, 0xac, 0x26, 0x00, 0xe9, 0x00, 0x00, 0x00, 0x00, 0x00}; // pkt2293
const uint8_t res10[] = {0xff, 0x0d, 0x02, 0x04, 0x02, 0x09, 0x07, 0x09, 0x02, 0x01, 0x04, 0xdc, 0x1e, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00}; // pkt3007
const uint8_t res11[] = {0xff, 0x0d, 0x02, 0x04, 0x02, 0x09, 0x07, 0x09, 0x02, 0x01, 0x04, 0x0c, 0x17, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00}; // pkt3502
const uint8_t res12[] = {0xff, 0x0d, 0x02, 0x04, 0x02, 0x09, 0x07, 0x09, 0x02, 0x01, 0x04, 0x24, 0x13, 0x00, 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00}; // pkt3578
const uint8_t res13[] = {0xff, 0x0d, 0x02, 0x04, 0x02, 0x09, 0x07, 0x09, 0x02, 0x01, 0x04, 0x3c, 0x0f, 0x00, 0x62, 0x00, 0x00, 0x00, 0x00, 0x00}; // pkt3666
const uint8_t res14[] = {0xff, 0x0d, 0x02, 0x04, 0x02, 0x09, 0x07, 0x09, 0x02, 0x01, 0x04, 0x54, 0x0b, 0x00, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00}; // pkt3740
const uint8_t res15[] = {0xff, 0x0d, 0x02, 0x04, 0x02, 0x09, 0x07, 0x09, 0x02, 0x01, 0x04, 0x6c, 0x07, 0x00, 0x8a, 0x00, 0x00, 0x00, 0x00, 0x00}; // pkt3824
const uint8_t res16[] = {0xff, 0x0d, 0x02, 0x04, 0x02, 0x09, 0x07, 0x09, 0x02, 0x01, 0x04, 0x84, 0x03, 0x00, 0x9e, 0x00, 0x00, 0x00, 0x00, 0x00}; // pkt3920
const uint8_t res17[] = {0xff, 0x0d, 0x02, 0x04, 0x02, 0x09, 0x07, 0x09, 0x02, 0x02, 0x00, 0x10, 0x04, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00}; // pkt4208
const uint8_t res18[] = {0xff, 0x0d, 0x02, 0x04, 0x02, 0x09, 0x07, 0x09, 0x02, 0x02, 0x00, 0x10, 0x01, 0x00, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00}; // pkt4227
const uint8_t res19[] = {0xff, 0x0d, 0x02, 0x04, 0x02, 0x09, 0x07, 0x09, 0x02, 0x02, 0x00, 0x10, 0x03, 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00}; // pkt4235
uint8_t noOpData7[] = {0xfe, 0x02, 0x0d, 0x02};
writeCharacteristic((uint8_t *)noOpData7, sizeof(noOpData7), QStringLiteral("resrequest"), false, false);
@@ -234,6 +243,33 @@ void proformbike::forceResistance(resistance_t requestResistance) {
case 10:
writeCharacteristic((uint8_t *)res10, sizeof(res10), QStringLiteral("resistance10"), false, true);
break;
case 11:
writeCharacteristic((uint8_t *)res11, sizeof(res11), QStringLiteral("resistance11"), false, true);
break;
case 12:
writeCharacteristic((uint8_t *)res12, sizeof(res12), QStringLiteral("resistance12"), false, true);
break;
case 13:
writeCharacteristic((uint8_t *)res13, sizeof(res13), QStringLiteral("resistance13"), false, true);
break;
case 14:
writeCharacteristic((uint8_t *)res14, sizeof(res14), QStringLiteral("resistance14"), false, true);
break;
case 15:
writeCharacteristic((uint8_t *)res15, sizeof(res15), QStringLiteral("resistance15"), false, true);
break;
case 16:
writeCharacteristic((uint8_t *)res16, sizeof(res16), QStringLiteral("resistance16"), false, true);
break;
case 17:
writeCharacteristic((uint8_t *)res17, sizeof(res17), QStringLiteral("resistance17"), false, true);
break;
case 18:
writeCharacteristic((uint8_t *)res18, sizeof(res18), QStringLiteral("resistance18"), false, true);
break;
case 19:
writeCharacteristic((uint8_t *)res19, sizeof(res19), QStringLiteral("resistance19"), false, true);
break;
}
} else if (proform_hybrid_trainer_PFEL03815 || proform_bike_sb) {
const uint8_t res1[] = {0xff, 0x0d, 0x02, 0x04, 0x02, 0x09, 0x07, 0x09, 0x02, 0x01,
@@ -322,7 +358,7 @@ void proformbike::forceResistance(resistance_t requestResistance) {
writeCharacteristic((uint8_t *)res16, sizeof(res16), QStringLiteral("resistance16"), false, true);
break;
}
} else if (nordictrack_gx_2_7 || proform_bike_225_csx || proform_225_csx_PFEX32925_INT_0) {
} else if (nordictrack_gx_2_7 || proform_bike_225_csx) {
const uint8_t res1[] = {0xff, 0x0d, 0x02, 0x04, 0x02, 0x09, 0x07, 0x09, 0x02, 0x01,
0x04, 0xc2, 0x01, 0x00, 0xda, 0x00, 0x00, 0x00, 0x00, 0x00};
const uint8_t res2[] = {0xff, 0x0d, 0x02, 0x04, 0x02, 0x09, 0x07, 0x09, 0x02, 0x01,
@@ -732,7 +768,7 @@ void proformbike::forceIncline(double incline) {
true);
}
bool proformbike::innerWriteResistance() {
void proformbike::innerWriteResistance() {
if (requestResistance != -1) {
if (requestResistance > max_resistance) {
requestResistance = max_resistance;
@@ -743,11 +779,9 @@ bool proformbike::innerWriteResistance() {
if (requestResistance != currentResistance().value()) {
emit debug(QStringLiteral("writing resistance ") + QString::number(requestResistance));
forceResistance(requestResistance);
return true;
}
requestResistance = -1;
}
return false;
}
void proformbike::update() {
@@ -880,7 +914,7 @@ void proformbike::update() {
switch (counterPoll) {
case 0:
if (nordictrack_gx_2_7 || proform_cycle_trainer_300_ci || proform_hybrid_trainer_PFEL03815 || proform_bike_sb || proform_bike_225_csx || proform_bike_325_csx || proform_xbike || proform_225_csx_PFEX32925_INT_0) {
if (nordictrack_gx_2_7 || proform_cycle_trainer_300_ci || proform_hybrid_trainer_PFEL03815 || proform_bike_sb || proform_bike_225_csx || proform_bike_325_csx || proform_xbike) {
writeCharacteristic(noOpData4, sizeof(noOpData4), QStringLiteral("noOp"));
} else if(proform_bike_PFEVEX71316_0) {
writeCharacteristic(noOpData1_proform_bike_PFEVEX71316_0, sizeof(noOpData1_proform_bike_PFEVEX71316_0), QStringLiteral("noOp"));
@@ -907,7 +941,7 @@ void proformbike::update() {
} else if (proform_tour_de_france_clc) {
writeCharacteristic(noOpData2_proform_tour_de_france_clc, sizeof(noOpData2_proform_tour_de_france_clc),
QStringLiteral("noOp"));
} else if (proform_bike_225_csx || proform_225_csx_PFEX32925_INT_0)
} else if (proform_bike_225_csx)
writeCharacteristic(noOpData2_proform_bike_225_csx, sizeof(noOpData2_proform_bike_225_csx),
QStringLiteral("noOp"));
else if (proform_cycle_trainer_400)
@@ -944,7 +978,7 @@ void proformbike::update() {
} else if (proform_cycle_trainer_400) {
writeCharacteristic(noOpData3_proform_cycle_trainer_400, sizeof(noOpData3_proform_cycle_trainer_400),
QStringLiteral("noOp"));
} else if (proform_bike_225_csx || proform_225_csx_PFEX32925_INT_0)
} else if (proform_bike_225_csx)
writeCharacteristic(noOpData3_proform_bike_225_csx, sizeof(noOpData3_proform_bike_225_csx),
QStringLiteral("noOp"));
else if (proform_bike_sb)
@@ -974,7 +1008,7 @@ void proformbike::update() {
} else if (proform_bike_sb || proform_bike_325_csx) {
innerWriteResistance();
writeCharacteristic(noOpData7, sizeof(noOpData7), QStringLiteral("noOp"));
} else if(proform_bike_225_csx || proform_225_csx_PFEX32925_INT_0) {
} else if(proform_bike_225_csx) {
writeCharacteristic(noOpData1, sizeof(noOpData1), QStringLiteral("noOp"));
} else
writeCharacteristic(noOpData4, sizeof(noOpData4), QStringLiteral("noOp"));
@@ -995,7 +1029,7 @@ void proformbike::update() {
} else if (proform_bike_325_csx) {
writeCharacteristic(noOpData5_proform_bike_325_csx, sizeof(noOpData5_proform_bike_325_csx),
QStringLiteral("noOp"));
} else if (proform_bike_225_csx || proform_225_csx_PFEX32925_INT_0) {
} else if (proform_bike_225_csx) {
writeCharacteristic(noOpData5_proform_bike_225_csx, sizeof(noOpData5_proform_bike_225_csx),
QStringLiteral("noOp"));
} else if (proform_bike_sb)
@@ -1015,7 +1049,9 @@ void proformbike::update() {
QStringLiteral("noOp"));
} else if(proform_bike_PFEVEX71316_0) {
writeCharacteristic(noOpData6_proform_bike_PFEVEX71316_0, sizeof(noOpData6_proform_bike_PFEVEX71316_0), QStringLiteral("noOp"), false, true);
if (!innerWriteResistance() && requestInclination != -100) {
if (requestResistance != -1)
innerWriteResistance();
else if (requestInclination != -100) {
writeCharacteristic(noOpData7, sizeof(noOpData7), QStringLiteral("noOp"));
// only 0.5 steps ara available
double inc = qRound(requestInclination * 2.0) / 2.0;
@@ -1026,9 +1062,9 @@ void proformbike::update() {
}
requestInclination = -100;
}
} else if (proform_bike_225_csx || proform_225_csx_PFEX32925_INT_0) {
} else if (proform_bike_225_csx) {
writeCharacteristic(noOpData6_proform_bike_225_csx, sizeof(noOpData6_proform_bike_225_csx),
QStringLiteral("noOp"), false, true);
QStringLiteral("noOp"));
innerWriteResistance();
}
else if (proform_cycle_trainer_400)
@@ -1064,7 +1100,7 @@ void proformbike::update() {
counterPoll++;
if (counterPoll > 6) {
counterPoll = 0;
} else if(counterPoll == 6 && (proform_bike_225_csx || proform_225_csx_PFEX32925_INT_0 || proform_bike_PFEVEX71316_0)) {
} else if(counterPoll == 6 && (proform_bike_225_csx || proform_bike_PFEVEX71316_0)) {
counterPoll = 0;
} else if (counterPoll == 6 &&
(proform_tour_de_france_clc || proform_cycle_trainer_400 || proform_bike_PFEVEX71316_1) &&
@@ -1575,12 +1611,10 @@ void proformbike::characteristicChanged(const QLowEnergyCharacteristic &characte
Resistance = 7;
m_pelotonResistance = 65;
break;
case 0x1e:
case 0x1f:
Resistance = 8;
m_pelotonResistance = 75;
break;
case 0x22:
case 0x23:
case 0x24:
Resistance = 9;
@@ -1859,8 +1893,6 @@ void proformbike::btinit() {
nordictrack_gx_44_pro = settings.value(QZSettings::nordictrack_gx_44_pro, QZSettings::default_nordictrack_gx_44_pro).toBool();
proform_bike_PFEVEX71316_0 = settings.value(QZSettings::proform_bike_PFEVEX71316_0, QZSettings::default_proform_bike_PFEVEX71316_0).toBool();
proform_xbike = settings.value(QZSettings::proform_xbike, QZSettings::default_proform_xbike).toBool();
proform_225_csx_PFEX32925_INT_0 = settings.value(QZSettings::proform_225_csx_PFEX32925_INT_0, QZSettings::default_proform_225_csx_PFEX32925_INT_0).toBool();
if(nordictrack_GX4_5_bike)
max_resistance = 25;
@@ -1925,159 +1957,6 @@ void proformbike::btinit() {
QThread::msleep(400);
writeCharacteristic(initData12, sizeof(initData12), QStringLiteral("init"), false, false);
QThread::msleep(400);
} else if (proform_225_csx_PFEX32925_INT_0) {
max_resistance = 20;
// Using the packet sequences from the 225 csx.c log file
uint8_t init1[] = {0xfe, 0x02, 0x08, 0x02};
uint8_t init2[] = {0xff, 0x08, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x81, 0x87,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
uint8_t init3[] = {0xfe, 0x02, 0x08, 0x02};
uint8_t init4[] = {0xff, 0x08, 0x02, 0x04, 0x02, 0x04, 0x07, 0x04, 0x80, 0x8b,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
uint8_t init5[] = {0xfe, 0x02, 0x08, 0x02};
uint8_t init6[] = {0xff, 0x08, 0x02, 0x04, 0x02, 0x04, 0x07, 0x04, 0x88, 0x93,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
uint8_t init7[] = {0xfe, 0x02, 0x0a, 0x02};
uint8_t init8[] = {0xff, 0x0a, 0x02, 0x04, 0x02, 0x06, 0x02, 0x06, 0x82, 0x00,
0x00, 0x8a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
uint8_t init9[] = {0xfe, 0x02, 0x0a, 0x02};
uint8_t init10[] = {0xff, 0x0a, 0x02, 0x04, 0x02, 0x06, 0x02, 0x06, 0x84, 0x00,
0x00, 0x8c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
uint8_t init11[] = {0xfe, 0x02, 0x08, 0x02};
uint8_t init12[] = {0xff, 0x08, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x95, 0x9b,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
uint8_t init13[] = {0xfe, 0x02, 0x2c, 0x04};
uint8_t init14[] = {0x00, 0x12, 0x02, 0x04, 0x02, 0x28, 0x07, 0x28, 0x90, 0x07,
0x01, 0xde, 0x84, 0x20, 0xca, 0x72, 0x28, 0xc4, 0x76, 0x26};
uint8_t init15[] = {0x01, 0x12, 0xec, 0x98, 0x42, 0x0a, 0xd0, 0x6c, 0x2e, 0xee,
0xd4, 0x90, 0x5a, 0x02, 0xf8, 0xb4, 0x66, 0x56, 0x3c, 0xe8};
uint8_t init16[] = {0xff, 0x08, 0xd2, 0xba, 0xa0, 0xa0, 0x02, 0x00, 0x00, 0x4f,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
uint8_t init17[] = {0xfe, 0x02, 0x19, 0x03};
uint8_t init18[] = {0x00, 0x12, 0x02, 0x04, 0x02, 0x15, 0x07, 0x15, 0x02, 0x0e,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
uint8_t init19[] = {0xff, 0x07, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x3d, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
uint8_t init20[] = {0xfe, 0x02, 0x17, 0x03};
uint8_t init21[] = {0x00, 0x12, 0x02, 0x04, 0x02, 0x13, 0x07, 0x13, 0x02, 0x0c,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
uint8_t init22[] = {0xff, 0x05, 0x00, 0x80, 0x01, 0x00, 0xa9, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
uint8_t init23[] = {0xfe, 0x02, 0x19, 0x03};
uint8_t init24[] = {0x00, 0x12, 0x02, 0x04, 0x02, 0x15, 0x07, 0x15, 0x02, 0x00,
0x0f, 0x00, 0x10, 0x00, 0xc0, 0x1c, 0x4c, 0x00, 0x00, 0xe0};
uint8_t init25[] = {0xff, 0x07, 0x00, 0x00, 0x00, 0x10, 0x00, 0x08, 0x5d, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
// Write the initialization sequence
writeCharacteristic(init1, sizeof(init1), QStringLiteral("init"), false, false);
QThread::msleep(400);
writeCharacteristic(init2, sizeof(init2), QStringLiteral("init"), false, false);
QThread::msleep(400);
writeCharacteristic(init3, sizeof(init3), QStringLiteral("init"), false, false);
QThread::msleep(400);
writeCharacteristic(init4, sizeof(init4), QStringLiteral("init"), false, false);
QThread::msleep(400);
writeCharacteristic(init5, sizeof(init5), QStringLiteral("init"), false, false);
QThread::msleep(400);
writeCharacteristic(init6, sizeof(init6), QStringLiteral("init"), false, false);
QThread::msleep(400);
writeCharacteristic(init7, sizeof(init7), QStringLiteral("init"), false, false);
QThread::msleep(400);
writeCharacteristic(init8, sizeof(init8), QStringLiteral("init"), false, false);
QThread::msleep(400);
writeCharacteristic(init9, sizeof(init9), QStringLiteral("init"), false, false);
QThread::msleep(400);
writeCharacteristic(init10, sizeof(init10), QStringLiteral("init"), false, false);
QThread::msleep(400);
writeCharacteristic(init11, sizeof(init11), QStringLiteral("init"), false, false);
QThread::msleep(400);
writeCharacteristic(init12, sizeof(init12), QStringLiteral("init"), false, false);
QThread::msleep(400);
writeCharacteristic(init13, sizeof(init13), QStringLiteral("init"), false, false);
QThread::msleep(400);
writeCharacteristic(init14, sizeof(init14), QStringLiteral("init"), false, false);
QThread::msleep(400);
writeCharacteristic(init15, sizeof(init15), QStringLiteral("init"), false, false);
QThread::msleep(400);
writeCharacteristic(init16, sizeof(init16), QStringLiteral("init"), false, false);
QThread::msleep(400);
writeCharacteristic(init17, sizeof(init17), QStringLiteral("init"), false, false);
QThread::msleep(400);
writeCharacteristic(init18, sizeof(init18), QStringLiteral("init"), false, false);
QThread::msleep(400);
writeCharacteristic(init19, sizeof(init19), QStringLiteral("init"), false, false);
QThread::msleep(400);
writeCharacteristic(init20, sizeof(init20), QStringLiteral("init"), false, false);
QThread::msleep(400);
writeCharacteristic(init21, sizeof(init21), QStringLiteral("init"), false, false);
QThread::msleep(400);
writeCharacteristic(init22, sizeof(init22), QStringLiteral("init"), false, false);
QThread::msleep(400);
writeCharacteristic(init23, sizeof(init23), QStringLiteral("init"), false, false);
QThread::msleep(400);
writeCharacteristic(init24, sizeof(init24), QStringLiteral("init"), false, false);
QThread::msleep(400);
writeCharacteristic(init25, sizeof(init25), QStringLiteral("init"), false, false);
QThread::msleep(400);
uint8_t init26[] = {0xfe, 0x02, 0x17, 0x03};
uint8_t init27[] = {0x00, 0x12, 0x02, 0x04, 0x02, 0x13, 0x07, 0x13, 0x02, 0x0c,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
uint8_t init28[] = {0xff, 0x05, 0x00, 0x80, 0x01, 0x00, 0xa9, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
uint8_t init29[] = {0xfe, 0x02, 0x17, 0x03};
uint8_t init30[] = {0x00, 0x12, 0x02, 0x04, 0x02, 0x13, 0x07, 0x13, 0x02, 0x0c,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
uint8_t init31[] = {0xff, 0x05, 0x00, 0x80, 0x00, 0x00, 0xa8, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
uint8_t init32[] = {0xfe, 0x02, 0x17, 0x03};
uint8_t init33[] = {0x00, 0x12, 0x02, 0x04, 0x02, 0x13, 0x07, 0x13, 0x02, 0x0c,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
uint8_t init34[] = {0xff, 0x05, 0x00, 0x80, 0x00, 0x00, 0xa8, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
uint8_t init35[] = {0xfe, 0x02, 0x17, 0x03};
uint8_t init36[] = {0x00, 0x12, 0x02, 0x04, 0x02, 0x13, 0x07, 0x13, 0x02, 0x00,
0x0d, 0x3c, 0x96, 0x31, 0x00, 0x00, 0x40, 0x40, 0x00, 0x80};
uint8_t init37[] = {0xff, 0x05, 0x00, 0x00, 0x00, 0x85, 0xb1, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
uint8_t init38[] = {0xfe, 0x02, 0x19, 0x03};
uint8_t init39[] = {0x00, 0x12, 0x02, 0x04, 0x02, 0x15, 0x07, 0x15, 0x02, 0x00,
0x0f, 0x80, 0x08, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
uint8_t init40[] = {0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x05, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
writeCharacteristic(init26, sizeof(init26), QStringLiteral("init"), false, false);
QThread::msleep(400);
writeCharacteristic(init27, sizeof(init27), QStringLiteral("init"), false, false);
QThread::msleep(400);
writeCharacteristic(init28, sizeof(init28), QStringLiteral("init"), false, false);
QThread::msleep(400);
writeCharacteristic(init29, sizeof(init29), QStringLiteral("init"), false, false);
QThread::msleep(400);
writeCharacteristic(init30, sizeof(init30), QStringLiteral("init"), false, false);
QThread::msleep(400);
writeCharacteristic(init31, sizeof(init31), QStringLiteral("init"), false, false);
QThread::msleep(400);
writeCharacteristic(init32, sizeof(init32), QStringLiteral("init"), false, false);
QThread::msleep(400);
writeCharacteristic(init33, sizeof(init33), QStringLiteral("init"), false, false);
QThread::msleep(400);
writeCharacteristic(init34, sizeof(init34), QStringLiteral("init"), false, false);
QThread::msleep(400);
writeCharacteristic(init35, sizeof(init35), QStringLiteral("init"), false, false);
QThread::msleep(400);
writeCharacteristic(init36, sizeof(init36), QStringLiteral("init"), false, false);
QThread::msleep(400);
writeCharacteristic(init37, sizeof(init37), QStringLiteral("init"), false, false);
QThread::msleep(400);
writeCharacteristic(init38, sizeof(init38), QStringLiteral("init"), false, false);
QThread::msleep(400);
writeCharacteristic(init39, sizeof(init39), QStringLiteral("init"), false, false);
QThread::msleep(400);
writeCharacteristic(init40, sizeof(init40), QStringLiteral("init"), false, false);
QThread::msleep(400);
} else if (settings.value(QZSettings::proform_xbike, QZSettings::default_proform_xbike).toBool()) {
max_resistance = 10;
@@ -2807,7 +2686,7 @@ void proformbike::btinit() {
writeCharacteristic(noOpData22, sizeof(noOpData22), QStringLiteral("init"), false, false);
QThread::msleep(400);
} else if (proform_bike_225_csx) {
max_resistance = 20;
max_resistance = 10;
uint8_t initData10[] = {0x00, 0x12, 0x02, 0x04, 0x02, 0x28, 0x07, 0x28, 0x90, 0x07, 0x01, 0xd2, 0x74, 0x14, 0xb2, 0x5e, 0x08, 0xa0, 0x5e, 0x0a};
uint8_t initData11[] = {0x01, 0x12, 0xbc, 0x6c, 0x1a, 0xc6, 0x90, 0x28, 0xe6, 0xa2, 0x64, 0x24, 0xe2, 0xae, 0x98, 0x50, 0x0e, 0xfa, 0xac, 0x9c};
uint8_t initData12[] = {0xff, 0x08, 0x4a, 0x36, 0x20, 0x98, 0x02, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

View File

@@ -55,7 +55,7 @@ class proformbike : public bike {
uint16_t watts() override;
void forceResistance(resistance_t requestResistance);
void forceIncline(double incline);
bool innerWriteResistance();
void innerWriteResistance();
QTimer *refresh;
uint8_t counterPoll = 0;
@@ -95,7 +95,6 @@ class proformbike : public bike {
bool nordictrack_gx_44_pro = false;
bool proform_bike_PFEVEX71316_0 = false;
bool proform_xbike = false;
bool proform_225_csx_PFEX32925_INT_0 = false;
#ifdef Q_OS_IOS
lockscreen *h = 0;

View File

@@ -271,15 +271,11 @@ void wahookickrsnapbike::update() {
}
if (lastGearValue != gears()) {
if(KICKR_SNAP) {
inclinationChanged(lastGrade, lastGrade);
} else {
QByteArray a = setWheelCircumference(wheelCircumference::gearsToWheelDiameter(gears()));
uint8_t b[20];
memcpy(b, a.constData(), a.length());
writeCharacteristic(b, a.length(), "setWheelCircumference", false, false);
lastGrade = 999; // to force a change
}
QByteArray a = setWheelCircumference(wheelCircumference::gearsToWheelDiameter(gears()));
uint8_t b[20];
memcpy(b, a.constData(), a.length());
writeCharacteristic(b, a.length(), "setWheelCircumference", false, false);
lastGrade = 999; // to force a change
}
lastGearValue = gears();
@@ -791,12 +787,8 @@ void wahookickrsnapbike::deviceDiscovered(const QBluetoothDeviceInfo &device) {
} else if(device.name().toUpper().startsWith("KICKR BIKE")) {
KICKR_BIKE = true;
qDebug() << "KICKR BIKE workaround activated";
} else if(device.name().toUpper().startsWith("KICKR SNAP")) {
KICKR_SNAP = true;
qDebug() << "KICKR SNAP workaround activated";
}
m_control = QLowEnergyController::createCentral(bluetoothDevice, this);
connect(m_control, &QLowEnergyController::serviceDiscovered, this, &wahookickrsnapbike::serviceDiscovered);
connect(m_control, &QLowEnergyController::discoveryFinished, this, &wahookickrsnapbike::serviceScanDone);
@@ -876,10 +868,6 @@ void wahookickrsnapbike::inclinationChanged(double grade, double percentage) {
emit debug(QStringLiteral("writing inclination ") + QString::number(grade));
QSettings settings;
double g = grade;
if(KICKR_SNAP) {
g += gears() * 0.5;
qDebug() << "adding gear offset so " << g;
}
QByteArray a = setSimGrade(g);
uint8_t b[20];
memcpy(b, a.constData(), a.length());

View File

@@ -107,7 +107,6 @@ class wahookickrsnapbike : public bike {
bool WAHOO_KICKR = false;
bool KICKR_BIKE = false;
bool KICKR_SNAP = false;
bool lastCommandErgMode = false;

View File

@@ -1,366 +0,0 @@
#include "gpiotreadmill.h"
#include "ios/lockscreen.h"
#include "keepawakehelper.h"
#include "virtualdevices/virtualtreadmill.h"
#include <QBluetoothLocalDevice>
#include <QDateTime>
#include <QFile>
#include <QMetaEnum>
#include <QSettings>
#include <chrono>
//#define Q_OS_RASPI 0
#ifdef Q_OS_RASPI
#include <wiringPi.h>
#else
#define OUTPUT 1
QModbusReply *gpiotreadmill::lastRequest;
QModbusClient *gpiotreadmill::modbusDevice = nullptr;
void gpiotreadmill::digitalWrite(int pin, int state) {
const int server_address = 255;
QModbusDataUnit writeUnit(QModbusDataUnit::Coils, pin, 1);
writeUnit.setValue(0, state);
if(modbusDevice) {
QModbusReply* r = nullptr;
int retry = 0;
do {
qDebug() << "modbus sending retry" << retry++;
r = modbusDevice->sendWriteRequest(writeUnit, server_address);
} while(r == nullptr);
}
else
qDebug() << "modbusDevice nullptr!";
qDebug() << QStringLiteral("switch pin ") + QString::number(pin) + QStringLiteral(" to ") + QString::number(state);
}
void pinMode(int pin, int state) {
qDebug() << QStringLiteral("init pin ") + QString::number(pin) + QStringLiteral(" to ") + QString::number(state);
}
int wiringPiSetup() {
return 0;
}
#endif
using namespace std::chrono_literals;
gpioWorkerThread::gpioWorkerThread(QObject *parent, QString name, uint8_t pinUp, uint8_t pinDown, double step, double currentValue, QSemaphore *semaphore): QThread(parent),
name{name}, currentValue{currentValue}, pinUp{pinUp}, pinDown{pinDown}, step{step}, semaphore{semaphore}
{
pinMode(pinUp, OUTPUT);
pinMode(pinDown, OUTPUT);
gpiotreadmill::digitalWrite(pinUp, 0);
gpiotreadmill::digitalWrite(pinDown, 0);
}
void gpioWorkerThread::setRequestValue(double request)
{
this->requestValue = request;
}
void gpioWorkerThread::run() {
if (requestValue > currentValue) {
while (requestValue > currentValue) {
qDebug() << QStringLiteral("increasing ") + name + " from " + QString::number(currentValue) + " to " + QString::number(requestValue);
semaphore->acquire();
gpiotreadmill::digitalWrite(pinUp, 1);
QThread::msleep(GPIO_KEEP_MS);
gpiotreadmill::digitalWrite(pinUp, 0);
QThread::msleep(GPIO_REBOUND_MS);
semaphore->release();
currentValue += step;
if(QThread::currentThread()->isInterruptionRequested()) {
qDebug() << "Interrupting set " + name;
return;
}
}
} else {
while (requestValue < currentValue) {
qDebug() << QStringLiteral("decreasing ") + name + " from " + QString::number(currentValue) + " to " + QString::number(requestValue);
semaphore->acquire();
gpiotreadmill::digitalWrite(pinDown, 1);
QThread::msleep(GPIO_KEEP_MS);
gpiotreadmill::digitalWrite(pinDown, 0);
QThread::msleep(GPIO_REBOUND_MS);
semaphore->release();
currentValue -= step;
if(QThread::currentThread()->isInterruptionRequested()) {
qDebug() << "Interrupting set " + name;
return;
}
}
}
QThread::msleep(50);
}
gpiotreadmill::gpiotreadmill(uint32_t pollDeviceTime, bool noConsole, bool noHeartService, double forceInitSpeed,
double forceInitInclination) {
m_watt.setType(metric::METRIC_WATT);
Speed.setType(metric::METRIC_SPEED);
this->noConsole = noConsole;
this->noHeartService = noHeartService;
if (wiringPiSetup() == -1) {
qDebug() << QStringLiteral("wiringPiSetup ERROR!");
exit(1);
}
modbusDevice = new QModbusRtuSerialMaster(this);
modbusDevice->setConnectionParameter(QModbusDevice::SerialPortNameParameter,
"COM4");
modbusDevice->setConnectionParameter(QModbusDevice::SerialParityParameter,
QSerialPort::Parity::NoParity);
modbusDevice->setConnectionParameter(QModbusDevice::SerialBaudRateParameter,
QSerialPort::Baud9600);
modbusDevice->setConnectionParameter(QModbusDevice::SerialDataBitsParameter,
QSerialPort::Data8);
modbusDevice->setConnectionParameter(QModbusDevice::SerialStopBitsParameter,
QSerialPort::StopBits::OneStop);
modbusDevice->setTimeout(50);
modbusDevice->setNumberOfRetries(3);
qDebug() << "modbus Connecting...";
while (!modbusDevice->connectDevice()) {
qDebug() << "modbus Connetion Error. Retrying...";
}
qDebug() << "modbus Connected!";
pinMode(OUTPUT_START, OUTPUT);
pinMode(OUTPUT_STOP, OUTPUT);
digitalWrite(OUTPUT_START, 0);
digitalWrite(OUTPUT_STOP, 0);
if (forceInitSpeed > 0) {
lastSpeed = forceInitSpeed;
}
if (forceInitInclination > 0) {
lastInclination = forceInitInclination;
}
semaphore = new QSemaphore(1);
speedThread = new gpioWorkerThread(this, "speed", OUTPUT_SPEED_UP, OUTPUT_SPEED_DOWN, SPEED_STEP, forceInitSpeed, semaphore);
inclineThread = new gpioWorkerThread(this, "incline", OUTPUT_INCLINE_UP, OUTPUT_INCLINE_DOWN, INCLINATION_STEP, forceInitInclination, semaphore);
refresh = new QTimer(this);
initDone = false;
connect(refresh, &QTimer::timeout, this, &gpiotreadmill::update);
refresh->start(pollDeviceTime);
Speed = 0.8;
}
gpiotreadmill::~gpiotreadmill() {
speedThread->requestInterruption();
speedThread->quit();
speedThread->wait();
delete speedThread;
inclineThread->requestInterruption();
inclineThread->quit();
inclineThread->wait();
delete inclineThread;
delete semaphore;
modbusDevice->disconnectDevice();
}
void gpiotreadmill::onReadReady() {
}
void gpiotreadmill::changeInclinationRequested(double grade, double percentage) {
if (percentage < 0)
percentage = 0;
changeInclination(grade, percentage);
}
void gpiotreadmill::forceSpeed(double requestSpeed) {
qDebug() << QStringLiteral("gpiotreadmill.cpp: request set speed ") + QString::number(Speed.value()) + QStringLiteral(" to ") + QString::number(requestSpeed);
if (speedThread->isRunning())
{
speedThread->requestInterruption();
speedThread->quit();
speedThread->wait();
}
speedThread->setRequestValue(requestSpeed);
speedThread->start();
Speed = requestSpeed; /* we are on the way to the requested speed */
}
void gpiotreadmill::forceIncline(double requestIncline) {
qDebug() << QStringLiteral("gpiotreadmill.cpp: request set Incline ") + QString::number(Inclination.value()) + QStringLiteral(" to ") + QString::number(requestIncline);
if (inclineThread->isRunning())
{
inclineThread->requestInterruption();
inclineThread->quit();
inclineThread->wait();
}
inclineThread->setRequestValue(requestIncline);
inclineThread->start();
Inclination = requestIncline; /* we are on the way to the requested incline */
}
void gpiotreadmill::update() {
QSettings settings;
// ******************************************* virtual treadmill init *************************************
if (!firstInit && !virtualTreadMill && !virtualBike) {
bool virtual_device_enabled = settings.value("virtual_device_enabled", true).toBool();
bool virtual_device_force_bike = settings.value("virtual_device_force_bike", false).toBool();
emit connectedAndDiscovered();
if (virtual_device_enabled) {
if (!virtual_device_force_bike) {
qDebug() << "creating virtual treadmill interface...";
virtualTreadMill = new virtualtreadmill(this, noHeartService);
connect(virtualTreadMill, &virtualtreadmill::debug, this, &gpiotreadmill::debug);
connect(virtualTreadMill, &virtualtreadmill::changeInclination, this,
&gpiotreadmill::changeInclinationRequested);
} else {
qDebug() <<"creating virtual bike interface...";
virtualBike = new virtualbike(this);
connect(virtualBike, &virtualbike::changeInclination, this, &gpiotreadmill::changeInclinationRequested);
}
firstInit = 1;
}
}
// ********************************************************************************************************
// debug("Domyos Treadmill RSSI " + QString::number(bluetoothDevice.rssi()));
double heart = 0;
QString heartRateBeltName =
settings.value(QStringLiteral("heart_rate_belt_name"), QStringLiteral("Disabled")).toString();
#ifdef Q_OS_ANDROID
if (settings.value("ant_heart", false).toBool())
Heart = (uint8_t)KeepAwakeHelper::heart();
else
#endif
{
if (heartRateBeltName.startsWith(QStringLiteral("Disabled"))) {
if (heart == 0) {
#ifdef Q_OS_IOS
#ifndef IO_UNDER_QT
lockscreen h;
long appleWatchHeartRate = h.heartRate();
h.setKcal(KCal.value());
h.setDistance(Distance.value());
Heart = appleWatchHeartRate;
qDebug() << "Current Heart from Apple Watch: " << QString::number(appleWatchHeartRate);
#endif
#endif
} else
Heart = heart;
}
}
if (!firstCharacteristicChanged) {
if (watts(settings.value(QStringLiteral("weight"), 75.0).toFloat()))
KCal +=
((((0.048 * ((double)watts(settings.value(QStringLiteral("weight"), 75.0).toFloat())) + 1.19) *
settings.value(QStringLiteral("weight"), 75.0).toFloat() * 3.5) /
200.0) /
(60000.0 / ((double)lastTimeCharacteristicChanged.msecsTo(
QDateTime::currentDateTime())))); //(( (0.048* Output in watts +1.19) * body weight in
// kg * 3.5) / 200 ) / 60
Distance += ((Speed.value() / (double)3600.0) /
((double)1000.0 / (double)(lastTimeCharacteristicChanged.msecsTo(QDateTime::currentDateTime()))));
lastTimeCharacteristicChanged = QDateTime::currentDateTime();
}
qDebug() << QStringLiteral("Current speed: ") + QString::number(Speed.value());
qDebug() << QStringLiteral("Current incline: ") + QString::number(Inclination.value());
qDebug() << QStringLiteral("Current heart: ") + QString::number(Heart.value());
qDebug() << QStringLiteral("Current KCal: ") + QString::number(KCal.value());
qDebug() << QStringLiteral("Current KCal from the machine: ") + QString::number(KCal.value());
qDebug() << QStringLiteral("Current Distance: ") + QString::number(Distance.value());
qDebug() << QStringLiteral("Current Distance Calculated: ") + QString::number(Distance.value());
firstCharacteristicChanged = false;
update_metrics(true, watts(settings.value(QStringLiteral("weight"), 75.0).toFloat()));
// updating the treadmill console every second
if (sec1Update++ >= (1000 / refresh->interval())) {
}
// byte 3 - 4 = elapsed time
// byte 17 = inclination
{
if (requestSpeed != -1) {
if (requestSpeed != currentSpeed().value() && requestSpeed >= 0 && requestSpeed <= 22) {
qDebug() << QStringLiteral("writing speed ") + QString::number(requestSpeed);
forceSpeed(requestSpeed);
}
requestSpeed = -1;
}
if (requestInclination != -1) {
// only 0.5 steps ara avaiable
requestInclination = qRound(requestInclination * 2.0) / 2.0;
if (requestInclination != currentInclination().value() && requestInclination >= 0 &&
requestInclination <= 15) {
qDebug() << QStringLiteral("writing incline ") + QString::number(requestInclination);
forceIncline(requestInclination);
}
requestInclination = -1;
}
if (requestStart != -1) {
qDebug() << QStringLiteral("starting...");
if (lastSpeed == 0.0) {
lastSpeed = 0.5;
}
digitalWrite(OUTPUT_START, 1);
QThread::msleep(GPIO_KEEP_MS);
digitalWrite(OUTPUT_START, 0);
requestStart = -1;
Speed = 0.8;
emit tapeStarted();
}
if (requestStop != -1) {
qDebug() << QStringLiteral("stopping...");
digitalWrite(OUTPUT_STOP, 1);
QThread::msleep(GPIO_KEEP_MS);
digitalWrite(OUTPUT_STOP, 0);
requestStop = -1;
}
if (requestFanSpeed != -1) {
qDebug() << QStringLiteral("changing fan speed...");
requestFanSpeed = -1;
}
if (requestIncreaseFan != -1) {
qDebug() << QStringLiteral("increasing fan speed...");
requestIncreaseFan = -1;
} else if (requestDecreaseFan != -1) {
qDebug() << QStringLiteral("decreasing fan speed...");
requestDecreaseFan = -1;
}
}
}
bool gpiotreadmill::connected() { return true; }
void *gpiotreadmill::VirtualTreadMill() { return virtualTreadMill; }
void *gpiotreadmill::VirtualDevice() { return VirtualTreadMill(); }
void gpiotreadmill::searchingStop() { searchStopped = true; }
double gpiotreadmill::minStepSpeed() { return 0.1; }

View File

@@ -1,140 +0,0 @@
#ifndef GPIOTREADMILL_H
#define GPIOTREADMILL_H
#include <QBluetoothDeviceDiscoveryAgent>
#include <QtBluetooth/qlowenergyadvertisingdata.h>
#include <QtBluetooth/qlowenergyadvertisingparameters.h>
#include <QtBluetooth/qlowenergycharacteristic.h>
#include <QtBluetooth/qlowenergycharacteristicdata.h>
#include <QtBluetooth/qlowenergycontroller.h>
#include <QtBluetooth/qlowenergydescriptordata.h>
#include <QtBluetooth/qlowenergyservice.h>
#include <QtBluetooth/qlowenergyservicedata.h>
#include <QtCore/qbytearray.h>
#ifndef Q_OS_ANDROID
#include <QtCore/qcoreapplication.h>
#else
#include <QtGui/qguiapplication.h>
#endif
#include <QtCore/qlist.h>
#include <QtCore/qmutex.h>
#include <QtCore/qscopedpointer.h>
#include <QtCore/qtimer.h>
#include <QDateTime>
#include <QObject>
#include <QThread>
#include <QSemaphore>
#include <QtSerialBus/QModbusClient>
#include <QtSerialBus/QModbusDataUnit>
#include <QtSerialBus/QModbusReply>
#include <QtSerialBus/QModbusRtuSerialMaster>
#include <QtSerialPort/QSerialPort>
#include "devices/treadmill.h"
#include "virtualdevices/virtualbike.h"
#include "virtualdevices/virtualtreadmill.h"
#ifdef Q_OS_IOS
#include "ios/lockscreen.h"
#endif
class gpioWorkerThread : public QThread
{
public:
explicit gpioWorkerThread(QObject *parent, QString name = "", uint8_t pinUp = 0, uint8_t pinDown = 0, double step = 0.0, double currentValue = 0.0, QSemaphore *semaphore = nullptr);
void run();
void setRequestValue(double request);
private:
QString name;
double requestValue;
double currentValue;
uint8_t pinUp;
uint8_t pinDown;
double step;
const uint16_t GPIO_KEEP_MS = 1;
const uint16_t GPIO_REBOUND_MS = 175;
QSemaphore *semaphore;
};
class gpiotreadmill : public treadmill {
Q_OBJECT
public:
gpiotreadmill(uint32_t poolDeviceTime = 200, bool noConsole = false, bool noHeartService = false,
double forceInitSpeed = 1.0, double forceInitInclination = 0.0);
~gpiotreadmill();
bool connected();
void *VirtualTreadMill();
void *VirtualDevice();
static void digitalWrite(int pin, int state);
static QModbusReply *lastRequest;
static QModbusClient *modbusDevice;
double minStepSpeed();
private:
bool noConsole = false;
bool noHeartService = false;
uint32_t pollDeviceTime = 200;
bool searchStopped = false;
uint8_t sec1Update = 0;
uint8_t firstInit = 0;
QDateTime lastTimeCharacteristicChanged;
bool firstCharacteristicChanged = true;
QTimer *refresh;
virtualtreadmill *virtualTreadMill = nullptr;
virtualbike *virtualBike = 0;
bool initDone = false;
bool initRequest = false;
const uint8_t OUTPUT_SPEED_UP = 0;
const uint8_t OUTPUT_SPEED_DOWN = 1;
const uint8_t OUTPUT_INCLINE_UP = 2;
const uint8_t OUTPUT_INCLINE_DOWN = 3;
const uint8_t OUTPUT_START = 4;
const uint8_t OUTPUT_STOP = 5;
const uint16_t GPIO_KEEP_MS = 50;
//const uint16_t GPIO_REBOUND_MS = 200;
const double SPEED_STEP = 0.1;
const double INCLINATION_STEP = 1.0;
void forceSpeed(double requestSpeed);
void forceIncline(double requestIncline);
gpioWorkerThread* speedThread;
gpioWorkerThread* inclineThread;
QSemaphore *semaphore; // my treadmill don't like it if the buttons will be pressed simultanly
#ifdef Q_OS_IOS
lockscreen *h = 0;
#endif
Q_SIGNALS:
void disconnected();
void debug(QString string);
void speedChanged(double speed);
void packetReceived();
public slots:
void searchingStop();
private slots:
void changeInclinationRequested(double grade, double percentage);
void onReadReady();
void update();
};
#endif // GPIOTREADMILL_H

View File

@@ -447,22 +447,6 @@ homeform::homeform(QQmlApplicationEngine *engine, bluetooth *bl) {
settings.value(QZSettings::tile_preset_powerzone_7_label, QZSettings::default_tile_preset_powerzone_7_label).toString(),
settings.value(QZSettings::tile_preset_powerzone_7_color, QZSettings::default_tile_preset_powerzone_7_color).toString());
tile_hr_time_in_zone_1 = new DataObject(QStringLiteral("HR Zone 1+"), QStringLiteral("icons/icons/heart_red.png"),
QStringLiteral("0:00:00"), false, QStringLiteral("tile_hr_time_in_zone_1"), valueElapsedFontSize, labelFontSize);
tile_hr_time_in_zone_2 = new DataObject(QStringLiteral("HR Zone 2+"), QStringLiteral("icons/icons/heart_red.png"),
QStringLiteral("0:00:00"), false, QStringLiteral("tile_hr_time_in_zone_2"), valueElapsedFontSize, labelFontSize);
tile_hr_time_in_zone_3 = new DataObject(QStringLiteral("HR Zone 3+"), QStringLiteral("icons/icons/heart_red.png"),
QStringLiteral("0:00:00"), false, QStringLiteral("tile_hr_time_in_zone_3"), valueElapsedFontSize, labelFontSize);
tile_hr_time_in_zone_4 = new DataObject(QStringLiteral("HR Zone 4+"), QStringLiteral("icons/icons/heart_red.png"),
QStringLiteral("0:00:00"), false, QStringLiteral("tile_hr_time_in_zone_4"), valueElapsedFontSize, labelFontSize);
tile_hr_time_in_zone_5 = new DataObject(QStringLiteral("HR Zone 5"), QStringLiteral("icons/icons/heart_red.png"),
QStringLiteral("0:00:00"), false, QStringLiteral("tile_hr_time_in_zone_5"), valueElapsedFontSize, labelFontSize);
if (!settings.value(QZSettings::top_bar_enabled, QZSettings::default_top_bar_enabled).toBool()) {
m_topBarHeight = 0;
@@ -1276,8 +1260,8 @@ void homeform::onToastRequested(QString message) {
QStringList homeform::tile_order() {
QStringList r;
r.reserve(65);
for (int i = 0; i < 66; i++) {
r.reserve(43);
for (int i = 0; i < 43; i++) {
r.append(QString::number(i));
}
return r;
@@ -1626,37 +1610,7 @@ void homeform::sortTiles() {
settings.value(QZSettings::tile_target_zone_order, 24).toInt() == i) {
target_zone->setGridId(i);
dataList.append(target_zone);
}
if (settings.value(QZSettings::tile_hr_time_in_zone_1_enabled, false).toBool() &&
settings.value(QZSettings::tile_hr_time_in_zone_1_order, 0).toInt() == i) {
tile_hr_time_in_zone_1->setGridId(i);
dataList.append(tile_hr_time_in_zone_1);
}
if (settings.value(QZSettings::tile_hr_time_in_zone_2_enabled, false).toBool() &&
settings.value(QZSettings::tile_hr_time_in_zone_2_order, 0).toInt() == i) {
tile_hr_time_in_zone_2->setGridId(i);
dataList.append(tile_hr_time_in_zone_2);
}
if (settings.value(QZSettings::tile_hr_time_in_zone_3_enabled, false).toBool() &&
settings.value(QZSettings::tile_hr_time_in_zone_3_order, 0).toInt() == i) {
tile_hr_time_in_zone_3->setGridId(i);
dataList.append(tile_hr_time_in_zone_3);
}
if (settings.value(QZSettings::tile_hr_time_in_zone_4_enabled, false).toBool() &&
settings.value(QZSettings::tile_hr_time_in_zone_4_order, 0).toInt() == i) {
tile_hr_time_in_zone_4->setGridId(i);
dataList.append(tile_hr_time_in_zone_4);
}
if (settings.value(QZSettings::tile_hr_time_in_zone_5_enabled, false).toBool() &&
settings.value(QZSettings::tile_hr_time_in_zone_5_order, 0).toInt() == i) {
tile_hr_time_in_zone_5->setGridId(i);
dataList.append(tile_hr_time_in_zone_5);
}
}
}
} else if (bluetoothManager->device()->deviceType() == bluetoothdevice::BIKE) {
for (int i = 0; i < 100; i++) {
@@ -2043,38 +1997,7 @@ void homeform::sortTiles() {
settings.value(QZSettings::tile_preset_powerzone_7_order, QZSettings::default_tile_preset_powerzone_7_order).toInt() == i) {
preset_powerzone_7->setGridId(i);
dataList.append(preset_powerzone_7);
}
if (settings.value(QZSettings::tile_hr_time_in_zone_1_enabled, false).toBool() &&
settings.value(QZSettings::tile_hr_time_in_zone_1_order, 0).toInt() == i) {
tile_hr_time_in_zone_1->setGridId(i);
dataList.append(tile_hr_time_in_zone_1);
}
if (settings.value(QZSettings::tile_hr_time_in_zone_2_enabled, false).toBool() &&
settings.value(QZSettings::tile_hr_time_in_zone_2_order, 0).toInt() == i) {
tile_hr_time_in_zone_2->setGridId(i);
dataList.append(tile_hr_time_in_zone_2);
}
if (settings.value(QZSettings::tile_hr_time_in_zone_3_enabled, false).toBool() &&
settings.value(QZSettings::tile_hr_time_in_zone_3_order, 0).toInt() == i) {
tile_hr_time_in_zone_3->setGridId(i);
dataList.append(tile_hr_time_in_zone_3);
}
if (settings.value(QZSettings::tile_hr_time_in_zone_4_enabled, false).toBool() &&
settings.value(QZSettings::tile_hr_time_in_zone_4_order, 0).toInt() == i) {
tile_hr_time_in_zone_4->setGridId(i);
dataList.append(tile_hr_time_in_zone_4);
}
if (settings.value(QZSettings::tile_hr_time_in_zone_5_enabled, false).toBool() &&
settings.value(QZSettings::tile_hr_time_in_zone_5_order, 0).toInt() == i) {
tile_hr_time_in_zone_5->setGridId(i);
dataList.append(tile_hr_time_in_zone_5);
}
}
}
} else if (bluetoothManager->device()->deviceType() == bluetoothdevice::ROWING) {
for (int i = 0; i < 100; i++) {
@@ -2367,38 +2290,7 @@ void homeform::sortTiles() {
settings.value(QZSettings::tile_gears_order, 51).toInt() == i) {
gears->setGridId(i);
dataList.append(gears);
}
if (settings.value(QZSettings::tile_hr_time_in_zone_1_enabled, false).toBool() &&
settings.value(QZSettings::tile_hr_time_in_zone_1_order, 0).toInt() == i) {
tile_hr_time_in_zone_1->setGridId(i);
dataList.append(tile_hr_time_in_zone_1);
}
if (settings.value(QZSettings::tile_hr_time_in_zone_2_enabled, false).toBool() &&
settings.value(QZSettings::tile_hr_time_in_zone_2_order, 0).toInt() == i) {
tile_hr_time_in_zone_2->setGridId(i);
dataList.append(tile_hr_time_in_zone_2);
}
if (settings.value(QZSettings::tile_hr_time_in_zone_3_enabled, false).toBool() &&
settings.value(QZSettings::tile_hr_time_in_zone_3_order, 0).toInt() == i) {
tile_hr_time_in_zone_3->setGridId(i);
dataList.append(tile_hr_time_in_zone_3);
}
if (settings.value(QZSettings::tile_hr_time_in_zone_4_enabled, false).toBool() &&
settings.value(QZSettings::tile_hr_time_in_zone_4_order, 0).toInt() == i) {
tile_hr_time_in_zone_4->setGridId(i);
dataList.append(tile_hr_time_in_zone_4);
}
if (settings.value(QZSettings::tile_hr_time_in_zone_5_enabled, false).toBool() &&
settings.value(QZSettings::tile_hr_time_in_zone_5_order, 0).toInt() == i) {
tile_hr_time_in_zone_5->setGridId(i);
dataList.append(tile_hr_time_in_zone_5);
}
}
}
} else if (bluetoothManager->device()->deviceType() == bluetoothdevice::JUMPROPE) {
for (int i = 0; i < 100; i++) {
@@ -2696,37 +2588,6 @@ void homeform::sortTiles() {
gears->setGridId(i);
dataList.append(gears);
}
if (settings.value(QZSettings::tile_hr_time_in_zone_1_enabled, false).toBool() &&
settings.value(QZSettings::tile_hr_time_in_zone_1_order, 0).toInt() == i) {
tile_hr_time_in_zone_1->setGridId(i);
dataList.append(tile_hr_time_in_zone_1);
}
if (settings.value(QZSettings::tile_hr_time_in_zone_2_enabled, false).toBool() &&
settings.value(QZSettings::tile_hr_time_in_zone_2_order, 0).toInt() == i) {
tile_hr_time_in_zone_2->setGridId(i);
dataList.append(tile_hr_time_in_zone_2);
}
if (settings.value(QZSettings::tile_hr_time_in_zone_3_enabled, false).toBool() &&
settings.value(QZSettings::tile_hr_time_in_zone_3_order, 0).toInt() == i) {
tile_hr_time_in_zone_3->setGridId(i);
dataList.append(tile_hr_time_in_zone_3);
}
if (settings.value(QZSettings::tile_hr_time_in_zone_4_enabled, false).toBool() &&
settings.value(QZSettings::tile_hr_time_in_zone_4_order, 0).toInt() == i) {
tile_hr_time_in_zone_4->setGridId(i);
dataList.append(tile_hr_time_in_zone_4);
}
if (settings.value(QZSettings::tile_hr_time_in_zone_5_enabled, false).toBool() &&
settings.value(QZSettings::tile_hr_time_in_zone_5_order, 0).toInt() == i) {
tile_hr_time_in_zone_5->setGridId(i);
dataList.append(tile_hr_time_in_zone_5);
}
}
} else if (bluetoothManager->device()->deviceType() == bluetoothdevice::ELLIPTICAL) {
for (int i = 0; i < 100; i++) {
@@ -3034,37 +2895,6 @@ void homeform::sortTiles() {
pace->setGridId(i);
dataList.append(pace);
}
if (settings.value(QZSettings::tile_hr_time_in_zone_1_enabled, false).toBool() &&
settings.value(QZSettings::tile_hr_time_in_zone_1_order, 0).toInt() == i) {
tile_hr_time_in_zone_1->setGridId(i);
dataList.append(tile_hr_time_in_zone_1);
}
if (settings.value(QZSettings::tile_hr_time_in_zone_2_enabled, false).toBool() &&
settings.value(QZSettings::tile_hr_time_in_zone_2_order, 0).toInt() == i) {
tile_hr_time_in_zone_2->setGridId(i);
dataList.append(tile_hr_time_in_zone_2);
}
if (settings.value(QZSettings::tile_hr_time_in_zone_3_enabled, false).toBool() &&
settings.value(QZSettings::tile_hr_time_in_zone_3_order, 0).toInt() == i) {
tile_hr_time_in_zone_3->setGridId(i);
dataList.append(tile_hr_time_in_zone_3);
}
if (settings.value(QZSettings::tile_hr_time_in_zone_4_enabled, false).toBool() &&
settings.value(QZSettings::tile_hr_time_in_zone_4_order, 0).toInt() == i) {
tile_hr_time_in_zone_4->setGridId(i);
dataList.append(tile_hr_time_in_zone_4);
}
if (settings.value(QZSettings::tile_hr_time_in_zone_5_enabled, false).toBool() &&
settings.value(QZSettings::tile_hr_time_in_zone_5_order, 0).toInt() == i) {
tile_hr_time_in_zone_5->setGridId(i);
dataList.append(tile_hr_time_in_zone_5);
}
}
}
@@ -3164,7 +2994,6 @@ void homeform::deviceConnected(QBluetoothDeviceInfo b) {
QObject::connect(home, SIGNAL(plus_clicked(QString)), this, SLOT(Plus(QString)));
QObject::connect(home, SIGNAL(minus_clicked(QString)), this, SLOT(Minus(QString)));
QObject::connect(home, SIGNAL(largeButton_clicked(QString)), this, SLOT(LargeButton(QString)));
QObject::connect(home, SIGNAL(keyPressed(int)), this, SLOT(keyPressed(int)));
emit workoutNameChanged(workoutName());
emit instructorNameChanged(instructorName());
@@ -3202,17 +3031,6 @@ void homeform::deviceConnected(QBluetoothDeviceInfo b) {
}
}
void homeform::keyPressed(int key) {
if(key == Qt::Key_A)
Plus("speed");
else if(key == Qt::Key_S)
Minus("speed");
else if(key == Qt::Key_D)
Plus("inclination");
else if(key == Qt::Key_F)
Minus("inclination");
}
void homeform::deviceFound(const QString &name) {
if (name.trimmed().isEmpty()) {
return;
@@ -4337,34 +4155,6 @@ void homeform::update() {
cm_inches_conversion = 0.393701;
}
// Get the time spent in each zone
uint32_t seconds_zone1 = bluetoothManager->device()->secondsForHeartZone(0);
uint32_t seconds_zone2 = bluetoothManager->device()->secondsForHeartZone(1);
uint32_t seconds_zone3 = bluetoothManager->device()->secondsForHeartZone(2);
uint32_t seconds_zone4 = bluetoothManager->device()->secondsForHeartZone(3);
uint32_t seconds_zone5 = bluetoothManager->device()->secondsForHeartZone(4);
// Calculate cumulative times (time in this zone or higher)
uint32_t seconds_zone1_plus = seconds_zone1 + seconds_zone2 + seconds_zone3 + seconds_zone4 + seconds_zone5;
uint32_t seconds_zone2_plus = seconds_zone2 + seconds_zone3 + seconds_zone4 + seconds_zone5;
uint32_t seconds_zone3_plus = seconds_zone3 + seconds_zone4 + seconds_zone5;
uint32_t seconds_zone4_plus = seconds_zone4 + seconds_zone5;
uint32_t seconds_zone5_plus = seconds_zone5; // Zone 5 is already just zone 5
// Update the UI for each tile
tile_hr_time_in_zone_1->setValue(QTime(0, 0, 0).addSecs(seconds_zone1_plus).toString("h:mm:ss"));
tile_hr_time_in_zone_2->setValue(QTime(0, 0, 0).addSecs(seconds_zone2_plus).toString("h:mm:ss"));
tile_hr_time_in_zone_3->setValue(QTime(0, 0, 0).addSecs(seconds_zone3_plus).toString("h:mm:ss"));
tile_hr_time_in_zone_4->setValue(QTime(0, 0, 0).addSecs(seconds_zone4_plus).toString("h:mm:ss"));
tile_hr_time_in_zone_5->setValue(QTime(0, 0, 0).addSecs(seconds_zone5_plus).toString("h:mm:ss"));
// Set colors based on the zone
tile_hr_time_in_zone_1->setValueFontColor(QStringLiteral("lightsteelblue"));
tile_hr_time_in_zone_2->setValueFontColor(QStringLiteral("green"));
tile_hr_time_in_zone_3->setValueFontColor(QStringLiteral("yellow"));
tile_hr_time_in_zone_4->setValueFontColor(QStringLiteral("orange"));
tile_hr_time_in_zone_5->setValueFontColor(QStringLiteral("red"));
emit signalChanged(signal());
emit currentSpeedChanged(bluetoothManager->device()->currentSpeed().value());
speed->setValue(QString::number(bluetoothManager->device()->currentSpeed().value() * unit_conversion, 'f', 1));
@@ -5653,8 +5443,7 @@ void homeform::update() {
delta = trainProgram->currentRow().loopTimeHR;
}
if (bluetoothManager->device()->deviceType() == bluetoothdevice::TREADMILL &&
!settings.value(QZSettings::trainprogram_pid_ignore_inclination, QZSettings::default_trainprogram_pid_ignore_inclination).toBool() &&
if (bluetoothManager->device()->deviceType() == bluetoothdevice::TREADMILL &&
bluetoothManager->device()->currentInclination().value() != lastInclination && lastWattage != 0) {
last_seconds_pid_heart_zone = seconds;
@@ -7534,15 +7323,12 @@ void homeform::loadSettings(const QUrl &filename) {
auto settings2LoadAllKeys = settings2Load.allKeys();
for (const QString &s : qAsConst(settings2LoadAllKeys)) {
if (!s.contains(QZSettings::cryptoKeySettingsProfiles)) {
// peloton refresh token must not be changed because it has one refresh token for peloton user saved locally on the device
if(!s.contains(QStringLiteral("peloton_refreshtoken"))) {
if (!s.contains(QStringLiteral("password")) && !s.contains(QStringLiteral("token"))) {
settings.setValue(s, settings2Load.value(s));
} else {
SimpleCrypt crypt;
crypt.setKey(cryptoKeySettingsProfiles());
settings.setValue(s, crypt.decryptToString(settings2Load.value(s).toString()));
}
if (!s.contains(QStringLiteral("password")) && !s.contains(QStringLiteral("token"))) {
settings.setValue(s, settings2Load.value(s));
} else {
SimpleCrypt crypt;
crypt.setKey(cryptoKeySettingsProfiles());
settings.setValue(s, crypt.decryptToString(settings2Load.value(s).toString()));
}
}
}

View File

@@ -693,12 +693,7 @@ class homeform : public QObject {
DataObject *preset_powerzone_4;
DataObject *preset_powerzone_5;
DataObject *preset_powerzone_6;
DataObject *preset_powerzone_7;
DataObject *tile_hr_time_in_zone_1;
DataObject *tile_hr_time_in_zone_2;
DataObject *tile_hr_time_in_zone_3;
DataObject *tile_hr_time_in_zone_4;
DataObject *tile_hr_time_in_zone_5;
DataObject *preset_powerzone_7;
private:
static homeform *m_singleton;
@@ -840,7 +835,6 @@ class homeform : public QObject {
void StopRequested();
void Lap();
void LargeButton(const QString &);
void keyPressed(int key);
void volumeDown();
void volumeUp();
void keyMediaPrevious();

View File

@@ -17,102 +17,64 @@ QT_USE_NAMESPACE
- (bool)cacheWriteValue:(const QByteArray &)value for:(NSObject *)obj
{
// Initial check for null object
if (!obj) {
qDebug() << "Error: Invalid object (nil)";
return false;
}
@autoreleasepool {
// Safely verify that the object is valid without calling methods on it
Class objClass = [obj class];
if (!objClass) {
qDebug() << "Error: Cannot get class of the object, probably deallocated";
@try {
// Accesso alle variabili private tramite self
OSXBluetooth::CharHash &localCharMap = ((QT_MANGLE_NAMESPACE(OSXBTCentralManager) *)self)->charMap;
OSXBluetooth::DescHash &localDescMap = ((QT_MANGLE_NAMESPACE(OSXBTCentralManager) *)self)->descMap;
OSXBluetooth::ValueHash &localValuesToWrite = ((QT_MANGLE_NAMESPACE(OSXBTCentralManager) *)self)->valuesToWrite;
// Verifica validità oggetto
if (!obj) {
qDebug() << "Error: Invalid object (nil)";
return false;
}
// Safe access to private variables
@try {
// Safely access private variables through self
QT_MANGLE_NAMESPACE(OSXBTCentralManager) *selfPtr = (QT_MANGLE_NAMESPACE(OSXBTCentralManager) *)self;
if (!selfPtr) {
qDebug() << "Error: Invalid self pointer";
return false;
}
OSXBluetooth::CharHash &localCharMap = selfPtr->charMap;
OSXBluetooth::DescHash &localDescMap = selfPtr->descMap;
OSXBluetooth::ValueHash &localValuesToWrite = selfPtr->valuesToWrite;
// Safely verify object type
BOOL isCharacteristic = NO;
BOOL isDescriptor = NO;
// Test with standard CoreBluetooth classes
const char *className = class_getName(objClass);
if (className) {
isCharacteristic = strcmp(className, "CBCharacteristic") == 0;
isDescriptor = strcmp(className, "CBDescriptor") == 0;
// Also check for subclasses
if (!isCharacteristic && !isDescriptor) {
Class charClass = NSClassFromString(@"CBCharacteristic");
Class descClass = NSClassFromString(@"CBDescriptor");
if (charClass && class_conformsToProtocol(objClass, @protocol(NSObject))) {
isCharacteristic = class_getSuperclass(objClass) == charClass;
}
if (descClass && class_conformsToProtocol(objClass, @protocol(NSObject))) {
isDescriptor = class_getSuperclass(objClass) == descClass;
}
}
}
// Verify based on identified type
if (isCharacteristic) {
CBCharacteristic *ch = (CBCharacteristic *)obj;
// Verify using only C functions to avoid Objective-C messages if possible
// Verifica tipo oggetto
if ([obj isKindOfClass:[CBCharacteristic class]]) {
@try {
CBCharacteristic *const ch = (CBCharacteristic *)obj;
if (!localCharMap.key(ch)) {
qDebug() << "Error: Unexpected characteristic, no handle found";
return false;
}
} else if (isDescriptor) {
CBDescriptor *d = (CBDescriptor *)obj;
} @catch (NSException *e) {
qDebug() << "Exception handling characteristic:" << e.reason;
return false;
}
} else if ([obj isKindOfClass:[CBDescriptor class]]) {
@try {
CBDescriptor *const d = (CBDescriptor *)obj;
if (!localDescMap.key(d)) {
qDebug() << "Error: Unexpected descriptor, no handle found";
return false;
}
} else {
qDebug() << "Error: Object is neither a characteristic nor a descriptor";
} @catch (NSException *e) {
qDebug() << "Exception handling descriptor:" << e.reason;
return false;
}
// Existing cache management with protection
} else {
qDebug() << "Error: Invalid object type, characteristic or descriptor required";
return false;
}
// Gestione cache esistente
@try {
if (localValuesToWrite.contains(obj)) {
qDebug() << "Warning: Already has a cached value for this object, the value will be replaced";
}
// Safe assignment
try {
localValuesToWrite[obj] = value;
} catch (const std::exception& e) {
qDebug() << "C++ exception during cache operation:" << e.what();
return false;
} catch (...) {
qDebug() << "Unknown C++ exception during cache operation";
return false;
}
return true;
localValuesToWrite[obj] = value;
} @catch (NSException *e) {
qDebug() << "Objective-C exception in cacheWriteValue:" << e.reason;
qDebug() << "Exception during cache operation:" << e.reason;
return false;
}
return true;
} @catch (NSException *e) {
qDebug() << "Unexpected exception in cacheWriteValue:" << e.reason;
return false;
}
// This point should never be reached due to previous returns
return false;
}
@end

View File

@@ -73,7 +73,6 @@ bool run_cadence_sensor = false;
bool horizon_treadmill_7_8 = false;
bool horizon_treadmill_force_ftms = false;
bool nordictrack_10_treadmill = false;
bool gpiotreadmill = true;
bool reebok_fr30_treadmill = false;
bool zwift_play = false;
bool zwift_click = false;
@@ -291,8 +290,6 @@ QCoreApplication *createApplication(int &argc, char *argv[]) {
horizon_treadmill_force_ftms = true;
if (!qstrcmp(argv[i], "-nordictrack-10-treadmill"))
nordictrack_10_treadmill = true;
if (!qstrcmp(argv[i], "-gpiotreadmill"))
gpiotreadmill = true;
if (!qstrcmp(argv[i], "-reebok_fr30_treadmill"))
reebok_fr30_treadmill = true;
if (!qstrcmp(argv[i], "-zwift_play"))
@@ -593,8 +590,6 @@ int main(int argc, char *argv[]) {
}
#endif
settings.setValue(QStringLiteral("gpio_treadmill"), gpiotreadmill);
#ifdef Q_OS_ANDROID
if (settings.value(QZSettings::volume_change_gears, QZSettings::default_volume_change_gears).toBool()) {
qDebug() << "handling volume keys";

View File

@@ -844,7 +844,7 @@ ApplicationWindow {
}
ItemDelegate {
text: "version 2.18.22"
text: "version 2.18.20"
width: parent.width
}
@@ -878,9 +878,6 @@ ApplicationWindow {
width: parent.width
onClicked: {
stackView.push("WebPelotonAuth.qml")
stackView.currentItem.goBack.connect(function() {
stackView.pop();
})
peloton_connect_clicked()
drawer.close()
}

View File

@@ -10,13 +10,12 @@
#include "homeform.h"
#include "peloton.h"
#include <chrono>
#include <QTimer>
using namespace std::chrono_literals;
const bool log_request = true;
#define RAWHEADER request.setHeader(QNetworkRequest::ContentTypeHeader, QStringLiteral("application/json"));request.setHeader(QNetworkRequest::UserAgentHeader, QStringLiteral("qdomyos-zwift"));request.setRawHeader(QByteArray("Authorization"), QByteArray("Bearer ") + getPelotonTokenForUser(QZSettings::peloton_accesstoken, userId, QZSettings::default_peloton_accesstoken).toString().toUtf8());
#define RAWHEADER request.setHeader(QNetworkRequest::ContentTypeHeader, QStringLiteral("application/json"));request.setHeader(QNetworkRequest::UserAgentHeader, QStringLiteral("qdomyos-zwift"));request.setRawHeader(QByteArray("Authorization"), QByteArray("Bearer ") + settings.value(QZSettings::peloton_accesstoken, QZSettings::default_peloton_accesstoken).toString().toUtf8());
peloton::peloton(bluetooth *bl, QObject *parent) : QObject(parent) {
@@ -35,6 +34,13 @@ peloton::peloton(bluetooth *bl, QObject *parent) : QObject(parent) {
"img_1646099287_a620f71b3d6740718457b21769a7ed46.png"));
*/
if (!settings.value(QZSettings::peloton_accesstoken, QZSettings::default_peloton_accesstoken)
.toString()
.length()) {
qDebug() << QStringLiteral("invalid peloton credentials");
return;
}
rower_pace_offset = 1;
rower_pace[0].value = -1;
@@ -596,13 +602,6 @@ peloton::peloton(bluetooth *bl, QObject *parent) : QObject(parent) {
connect(PZP, &powerzonepack::loginState, this, &peloton::pzp_loginState);
connect(HFB, &homefitnessbuddy::workoutStarted, this, &peloton::hfb_trainrows);
if (!settings.value(QZSettings::peloton_accesstoken, QZSettings::default_peloton_accesstoken)
.toString()
.length()) {
qDebug() << QStringLiteral("invalid peloton credentials");
return;
}
startEngine();
}
@@ -641,7 +640,6 @@ void peloton::startEngine() {
}
QSettings settings;
QString userId = settings.value(QZSettings::peloton_current_user_id).toString();
timer->stop();
connect(mgr, &QNetworkAccessManager::finished, this, &peloton::login_onfinish);
@@ -651,7 +649,7 @@ void peloton::startEngine() {
RAWHEADER
//qDebug() << getPelotonTokenForUser(QZSettings::peloton_accesstoken, userId, QZSettings::default_peloton_accesstoken).toString().toLatin1() << request.rawHeader(QByteArray("authorization"));
qDebug() << settings.value(QZSettings::peloton_accesstoken, QZSettings::default_peloton_accesstoken).toString().toLatin1() << request.rawHeader(QByteArray("authorization"));
mgr->get(request);
}
@@ -670,13 +668,6 @@ void peloton::login_onfinish(QNetworkReply *reply) {
} else {
qDebug() << QStringLiteral("login_onfinish");
}
// Check if document is empty, and if so, retry after 5 seconds
if (document.isEmpty()) {
qDebug() << QStringLiteral("login_onfinish: Empty document received, retrying in 5 seconds");
QTimer::singleShot(5000, this, &peloton::startEngine);
return;
}
if (status != 0) {
@@ -690,16 +681,6 @@ void peloton::login_onfinish(QNetworkReply *reply) {
user_id = document[QStringLiteral("id")].toString();
total_workout = document[QStringLiteral("total_workouts")].toInt();
QSettings settings;
// if it's a new user
if(user_id.compare(settings.value(QZSettings::peloton_current_user_id, QZSettings::default_peloton_current_user_id).toString())) {
qDebug() << "new peloton user id, saving information...";
settings.setValue(QZSettings::peloton_current_user_id, user_id);
settings.setValue(getPelotonSettingKey(QZSettings::peloton_refreshtoken, user_id), settings.value(QZSettings::peloton_refreshtoken, QZSettings::default_peloton_refreshtoken).toString());
settings.setValue(getPelotonSettingKey(QZSettings::peloton_accesstoken, user_id), settings.value(QZSettings::peloton_accesstoken, QZSettings::default_peloton_accesstoken).toString());
}
qDebug() << "user_id" << user_id << "total workout" << total_workout;
emit loginState(!user_id.isEmpty());
@@ -777,8 +758,6 @@ void peloton::summary_onfinish(QNetworkReply *reply) {
qDebug() << QStringLiteral("peloton::summary_onfinish");
}
workout_retry_count = 0;
getWorkout(current_workout_id);
}
@@ -834,20 +813,6 @@ void peloton::workout_onfinish(QNetworkReply *reply) {
QByteArray payload = reply->readAll(); // JSON
QJsonParseError parseError;
workout = QJsonDocument::fromJson(payload, &parseError);
if (workout.isNull() && workout_retry_count < 3) {
workout_retry_count++;
qDebug() << "Empty JSON document received, retry attempt" << workout_retry_count;
QTimer::singleShot(2000, this, [this]() {
getWorkout(current_workout_id);
});
return;
} else if (workout.isNull() && workout_retry_count >= 3) {
if(homeform::singleton())
homeform::singleton()->setToastRequested("Error: Failed to load workout data after 3 attempts");
}
workout_retry_count = 0;
QJsonObject ride = workout.object()[QStringLiteral("ride")].toObject();
current_workout_name = ride[QStringLiteral("title")].toString();
current_instructor_id = ride[QStringLiteral("instructor_id")].toString();
@@ -1297,14 +1262,9 @@ void peloton::ride_onfinish(QNetworkReply *reply) {
QJsonArray metrics = segmentObj["metrics"].toArray();
QJsonObject offsets = segmentObj["offsets"].toObject();
QString segment_type = segmentObj["segment_type"].toString();
bool floorSegment = false;
if(segment_type.startsWith("floor")) { // bootcamp
floorSegment = true;
}
// Skip if no metrics or invalid offsets
if ((metrics.isEmpty() || offsets.isEmpty()) && !floorSegment)
if (metrics.isEmpty() || offsets.isEmpty())
continue;
double speed_lower = -1;
@@ -1887,7 +1847,6 @@ double peloton::rowerpaceToSpeed(double pace) {
void peloton::getInstructor(const QString &instructor_id) {
QSettings settings;
QString userId = settings.value(QZSettings::peloton_current_user_id).toString();
connect(mgr, &QNetworkAccessManager::finished, this, &peloton::instructor_onfinish);
QUrl url(QStringLiteral("https://api-3p.onepeloton.com/api/v1/instructor/") + instructor_id);
@@ -1901,7 +1860,6 @@ void peloton::getInstructor(const QString &instructor_id) {
void peloton::getRide(const QString &ride_id) {
QSettings settings;
QString userId = settings.value(QZSettings::peloton_current_user_id).toString();
connect(mgr, &QNetworkAccessManager::finished, this, &peloton::ride_onfinish);
QUrl url(QStringLiteral("https://api-3p.onepeloton.com/api/v1/ride/") + ride_id +
@@ -1916,7 +1874,6 @@ void peloton::getRide(const QString &ride_id) {
void peloton::getPerformance(const QString &workout) {
QSettings settings;
QString userId = settings.value(QZSettings::peloton_current_user_id).toString();
connect(mgr, &QNetworkAccessManager::finished, this, &peloton::performance_onfinish);
QUrl url(QStringLiteral("https://api-3p.onepeloton.com/api/v1/workout/") + workout +
@@ -1931,7 +1888,6 @@ void peloton::getPerformance(const QString &workout) {
void peloton::getWorkout(const QString &workout) {
QSettings settings;
QString userId = settings.value(QZSettings::peloton_current_user_id).toString();
connect(mgr, &QNetworkAccessManager::finished, this, &peloton::workout_onfinish);
QUrl url(QStringLiteral("https://api-3p.onepeloton.com/api/v1/workout/") + workout);
@@ -1945,7 +1901,6 @@ void peloton::getWorkout(const QString &workout) {
void peloton::getSummary(const QString &workout) {
QSettings settings;
QString userId = settings.value(QZSettings::peloton_current_user_id).toString();
connect(mgr, &QNetworkAccessManager::finished, this, &peloton::summary_onfinish);
QUrl url(QStringLiteral("https://api-3p.onepeloton.com/api/v1/workout/") + workout + QStringLiteral("/summary"));
@@ -1960,7 +1915,6 @@ void peloton::getSummary(const QString &workout) {
void peloton::getWorkoutList(int num) {
Q_UNUSED(num)
QSettings settings;
QString userId = settings.value(QZSettings::peloton_current_user_id).toString();
// if (num == 0) { //NOTE: clang-analyzer-deadcode.DeadStores
// num = this->total_workout;
// }
@@ -1991,16 +1945,13 @@ void peloton::onPelotonGranted() {
pelotonAuthWebVisible = false;
emit pelotonWebVisibleChanged(pelotonAuthWebVisible);
QSettings settings;
QString userId = settings.value(QZSettings::peloton_current_user_id).toString();
savePelotonTokenForUser(QZSettings::peloton_accesstoken, pelotonOAuth->token(), userId);
savePelotonTokenForUser(QZSettings::peloton_refreshtoken, pelotonOAuth->refreshToken(), userId);
savePelotonTokenForUser(QZSettings::peloton_lastrefresh, QDateTime::currentDateTime(), userId);
settings.setValue(QZSettings::peloton_accesstoken, pelotonOAuth->token());
settings.setValue(QZSettings::peloton_refreshtoken, pelotonOAuth->refreshToken());
settings.setValue(QZSettings::peloton_lastrefresh, QDateTime::currentDateTime());
qDebug() << QStringLiteral("peloton authenticathed") << pelotonOAuth->token() << pelotonOAuth->refreshToken();
peloton_refreshtoken();
if(homeform::singleton())
homeform::singleton()->setPelotonPopupVisible(true);
if(!timer->isActive())
startEngine();
}
void peloton::onPelotonAuthorizeWithBrowser(const QUrl &url) {
@@ -2030,12 +1981,11 @@ void peloton::replyDataReceived(const QByteArray &v) {
QByteArray data;
QSettings settings;
QString userId = settings.value(QZSettings::peloton_current_user_id).toString();
QString s(v);
QJsonDocument jsonResponse = QJsonDocument::fromJson(s.toUtf8());
savePelotonTokenForUser(QZSettings::peloton_accesstoken, jsonResponse[QStringLiteral("access_token")], userId);
savePelotonTokenForUser(QZSettings::peloton_refreshtoken, jsonResponse[QStringLiteral("refresh_token")], userId);
savePelotonTokenForUser(QZSettings::peloton_expires, jsonResponse[QStringLiteral("expires_at")], userId);
settings.setValue(QZSettings::peloton_accesstoken, jsonResponse[QStringLiteral("access_token")]);
settings.setValue(QZSettings::peloton_refreshtoken, jsonResponse[QStringLiteral("refresh_token")]);
settings.setValue(QZSettings::peloton_expires, jsonResponse[QStringLiteral("expires_at")]);
qDebug() << jsonResponse[QStringLiteral("access_token")] << jsonResponse[QStringLiteral("refresh_token")]
<< jsonResponse[QStringLiteral("expires_at")];
@@ -2080,7 +2030,6 @@ void peloton::onSslErrors(QNetworkReply *reply, const QList<QSslError> &error) {
void peloton::networkRequestFinished(QNetworkReply *reply) {
QSettings settings;
QString userId = settings.value(QZSettings::peloton_current_user_id).toString();
// we can handle SSL handshake errors, if we got here then some kind of protocol was agreed
if (reply->error() == QNetworkReply::NoError || reply->error() == QNetworkReply::SslHandshakeFailedError) {
@@ -2098,9 +2047,9 @@ void peloton::networkRequestFinished(QNetworkReply *reply) {
access_token = document[QStringLiteral("access_token")].toString();
}
savePelotonTokenForUser(QZSettings::peloton_accesstoken, access_token, userId);
savePelotonTokenForUser(QZSettings::peloton_refreshtoken, refresh_token, userId);
savePelotonTokenForUser(QZSettings::peloton_lastrefresh, QDateTime::currentDateTime(), userId);
settings.setValue(QZSettings::peloton_accesstoken, access_token);
settings.setValue(QZSettings::peloton_refreshtoken, refresh_token);
settings.setValue(QZSettings::peloton_lastrefresh, QDateTime::currentDateTime());
qDebug() << access_token << refresh_token;
@@ -2191,14 +2140,10 @@ void peloton::peloton_refreshtoken() {
QSettings settings;
// QUrlQuery params; //NOTE: clazy-unuse-non-tirial-variable
QString userId = settings.value(QZSettings::peloton_current_user_id).toString();
if (settings.value(QZSettings::peloton_refreshtoken).toString().isEmpty()) {
// If no user is logged in yet, just use the regular method
if (userId.isEmpty()) {
if (settings.value(QZSettings::peloton_refreshtoken).toString().isEmpty()) {
peloton_connect();
return;
}
peloton_connect();
return;
}
QNetworkRequest request(QUrl(QStringLiteral("https://auth.onepeloton.com/oauth/token?")));
@@ -2207,7 +2152,7 @@ void peloton::peloton_refreshtoken() {
// set params
QString data;
data += QStringLiteral("client_id=" PELOTON_CLIENT_ID_S);
data += QStringLiteral("&refresh_token=") + getPelotonTokenForUser(QZSettings::peloton_refreshtoken, userId).toString();
data += QStringLiteral("&refresh_token=") + settings.value(QZSettings::peloton_refreshtoken).toString();
data += QStringLiteral("&grant_type=refresh_token");
// make request
@@ -2229,8 +2174,7 @@ void peloton::peloton_refreshtoken() {
// oops, no dice
if (reply->error() != 0) {
homeform::singleton()->setToastRequested("Peloton Auth Failed!");
qDebug() << QStringLiteral("Got error") << reply->errorString().toStdString().c_str();
qDebug() << QStringLiteral("Got error") << reply->errorString().toStdString().c_str();
return;
}
@@ -2249,10 +2193,9 @@ void peloton::peloton_refreshtoken() {
QString access_token = document[QStringLiteral("access_token")].toString();
QString refresh_token = document[QStringLiteral("refresh_token")].toString();
qDebug() << "userid: " << userId;
savePelotonTokenForUser(QZSettings::peloton_accesstoken, access_token, userId);
savePelotonTokenForUser(QZSettings::peloton_refreshtoken, refresh_token, userId);
savePelotonTokenForUser(QZSettings::peloton_lastrefresh, QDateTime::currentDateTime(), userId);
settings.setValue(QZSettings::peloton_accesstoken, access_token);
settings.setValue(QZSettings::peloton_refreshtoken, refresh_token);
settings.setValue(QZSettings::peloton_lastrefresh, QDateTime::currentDateTime());
homeform::singleton()->setToastRequested("Peloton Login OK!");

View File

@@ -72,7 +72,6 @@ class peloton : public QObject {
private:
_PELOTON_API current_api = peloton_api;
const int peloton_workout_second_resolution = 1;
int workout_retry_count = 0;
bool peloton_credentials_wrong = false;
QNetworkAccessManager *mgr = nullptr;
@@ -108,22 +107,6 @@ class peloton : public QObject {
QNetworkReply *replyPeloton;
QAbstractOAuth::ModifyParametersFunction buildModifyParametersFunction(const QUrl &clientIdentifier,
const QUrl &clientIdentifierSharedKey);
// Save token with user-specific suffix
QString getPelotonSettingKey(const QString& baseKey, const QString& userId) {
if (userId.isEmpty()) {
qDebug() << "ERROR: userid is empty!";
return baseKey; // If no user ID, use the default key
}
return baseKey + "_" + userId;
}
void savePelotonTokenForUser(const QString& baseKey, const QVariant& value, const QString& userId) {
QSettings settings;
settings.setValue(getPelotonSettingKey(baseKey, userId), value);
}
QVariant getPelotonTokenForUser(const QString& baseKey, const QString& userId, const QVariant& defaultValue = "") {
QSettings settings;
return settings.value(getPelotonSettingKey(baseKey, userId), defaultValue).toString();
}
// rowers
double rowerpaceToSpeed(double pace);

View File

@@ -3,9 +3,6 @@ QT += bluetooth widgets xml positioning quick networkauth websockets texttospeec
QTPLUGIN += qavfmediaplayer
QT+= charts core-private
win32: QT += serialport serialbus
linux:!android: QT += serialport serialbus
qtHaveModule(httpserver) {
QT += httpserver
DEFINES += Q_HTTPSERVER
@@ -324,10 +321,6 @@ zwiftworkout.cpp
macx: SOURCES += macos/lockscreen.mm
!ios: SOURCES += mainwindow.cpp charts.cpp
#gpio treadmill
win32: SOURCES += gpiotreadmill.cpp
linux:!android: SOURCES += gpiotreadmill.cpp
#zwift api
msvc {
SOURCES += zwift-api/zwift_messages.pb.cc
@@ -826,9 +819,6 @@ windows_zwift_incline_paddleocr_thread.h \
zwiftworkout.h
win32: HEADERS += gpiotreadmill.h
linux:!android: HEADERS += gpiotreadmill.h
exists(secret.h): HEADERS += secret.h
!ios: HEADERS += charts.h
@@ -965,4 +955,4 @@ INCLUDEPATH += purchasing/inapp
WINRT_MANIFEST = AppxManifest.xml
VERSION = 2.18.22
VERSION = 2.18.20

View File

@@ -887,27 +887,8 @@ const QString QZSettings::real_inclination_to_virtual_treamill_bridge = QStringL
const QString QZSettings::stryd_inclination_instead_treadmill = QStringLiteral("stryd_inclination_instead_treadmill");
const QString QZSettings::domyos_elliptical_fmts = QStringLiteral("domyos_elliptical_fmts");
const QString QZSettings::proform_xbike = QStringLiteral("proform_xbike");
const QString QZSettings::peloton_current_user_id = QStringLiteral("peloton_current_user_id");
const QString QZSettings::default_peloton_current_user_id = QStringLiteral("");
const QString QZSettings::proform_225_csx_PFEX32925_INT_0 = QStringLiteral("proform_225_csx_PFEX32925_INT_0");
const QString QZSettings::trainprogram_pid_ignore_inclination = QStringLiteral("trainprogram_pid_ignore_inclination");
const QString QZSettings::tile_hr_time_in_zone_1_enabled = QStringLiteral("tile_hr_time_in_zone_1_enabled");
const QString QZSettings::tile_hr_time_in_zone_1_order = QStringLiteral("tile_hr_time_in_zone_1_order");
const QString QZSettings::tile_hr_time_in_zone_2_enabled = QStringLiteral("tile_hr_time_in_zone_2_enabled");
const QString QZSettings::tile_hr_time_in_zone_2_order = QStringLiteral("tile_hr_time_in_zone_2_order");
const QString QZSettings::tile_hr_time_in_zone_3_enabled = QStringLiteral("tile_hr_time_in_zone_3_enabled");
const QString QZSettings::tile_hr_time_in_zone_3_order = QStringLiteral("tile_hr_time_in_zone_3_order");
const QString QZSettings::tile_hr_time_in_zone_4_enabled = QStringLiteral("tile_hr_time_in_zone_4_enabled");
const QString QZSettings::tile_hr_time_in_zone_4_order = QStringLiteral("tile_hr_time_in_zone_4_order");
const QString QZSettings::tile_hr_time_in_zone_5_enabled = QStringLiteral("tile_hr_time_in_zone_5_enabled");
const QString QZSettings::tile_hr_time_in_zone_5_order = QStringLiteral("tile_hr_time_in_zone_5_order");
const uint32_t allSettingsCount = 746;
const uint32_t allSettingsCount = 733;
QVariant allSettings[allSettingsCount][2] = {
{QZSettings::cryptoKeySettingsProfiles, QZSettings::default_cryptoKeySettingsProfiles},
@@ -1655,20 +1636,6 @@ QVariant allSettings[allSettingsCount][2] = {
{QZSettings::stryd_inclination_instead_treadmill, QZSettings::default_stryd_inclination_instead_treadmill},
{QZSettings::domyos_elliptical_fmts, QZSettings::default_domyos_elliptical_fmts},
{QZSettings::proform_xbike, QZSettings::default_proform_xbike},
{QZSettings::peloton_current_user_id, QZSettings::default_peloton_current_user_id},
{QZSettings::proform_225_csx_PFEX32925_INT_0, QZSettings::proform_225_csx_PFEX32925_INT_0},
{QZSettings::trainprogram_pid_ignore_inclination, QZSettings::default_trainprogram_pid_ignore_inclination},
{QZSettings::tile_hr_time_in_zone_1_enabled, QZSettings::default_tile_hr_time_in_zone_1_enabled},
{QZSettings::tile_hr_time_in_zone_1_order, QZSettings::default_tile_hr_time_in_zone_1_order},
{QZSettings::tile_hr_time_in_zone_2_enabled, QZSettings::default_tile_hr_time_in_zone_2_enabled},
{QZSettings::tile_hr_time_in_zone_2_order, QZSettings::default_tile_hr_time_in_zone_2_order},
{QZSettings::tile_hr_time_in_zone_3_enabled, QZSettings::default_tile_hr_time_in_zone_3_enabled},
{QZSettings::tile_hr_time_in_zone_3_order, QZSettings::default_tile_hr_time_in_zone_3_order},
{QZSettings::tile_hr_time_in_zone_4_enabled, QZSettings::default_tile_hr_time_in_zone_4_enabled},
{QZSettings::tile_hr_time_in_zone_4_order, QZSettings::default_tile_hr_time_in_zone_4_order},
{QZSettings::tile_hr_time_in_zone_5_enabled, QZSettings::default_tile_hr_time_in_zone_5_enabled},
{QZSettings::tile_hr_time_in_zone_5_order, QZSettings::default_tile_hr_time_in_zone_5_order},
};
void QZSettings::qDebugAllSettings(bool showDefaults) {

View File

@@ -2399,43 +2399,6 @@ class QZSettings {
static const QString proform_xbike;
static constexpr bool default_proform_xbike = false;
static const QString peloton_current_user_id;
static const QString default_peloton_current_user_id;
static const QString proform_225_csx_PFEX32925_INT_0;
static constexpr bool default_proform_225_csx_PFEX32925_INT_0 = false;
static const QString trainprogram_pid_ignore_inclination;
static constexpr bool default_trainprogram_pid_ignore_inclination = false;
static const QString tile_hr_time_in_zone_1_enabled;
static constexpr bool default_tile_hr_time_in_zone_1_enabled = false;
static const QString tile_hr_time_in_zone_1_order;
static constexpr int default_tile_hr_time_in_zone_1_order = 62;
static const QString tile_hr_time_in_zone_2_enabled;
static constexpr bool default_tile_hr_time_in_zone_2_enabled = false;
static const QString tile_hr_time_in_zone_2_order;
static constexpr int default_tile_hr_time_in_zone_2_order = 63;
static const QString tile_hr_time_in_zone_3_enabled;
static constexpr bool default_tile_hr_time_in_zone_3_enabled = false;
static const QString tile_hr_time_in_zone_3_order;
static constexpr int default_tile_hr_time_in_zone_3_order = 64;
static const QString tile_hr_time_in_zone_4_enabled;
static constexpr bool default_tile_hr_time_in_zone_4_enabled = false;
static const QString tile_hr_time_in_zone_4_order;
static constexpr int default_tile_hr_time_in_zone_4_order = 65;
static const QString tile_hr_time_in_zone_5_enabled;
static constexpr bool default_tile_hr_time_in_zone_5_enabled = false;
static const QString tile_hr_time_in_zone_5_order;
static constexpr int default_tile_hr_time_in_zone_5_order = 66;
/**
* @brief Write the QSettings values using the constants from this namespace.
* @param showDefaults Optionally indicates if the default should be shown with the key.

View File

@@ -238,17 +238,6 @@ ScrollView {
property real tile_preset_powerzone_7_value: 7.0
property string tile_preset_powerzone_7_label: "Zone 7"
property string tile_preset_powerzone_7_color: "red"
property bool tile_hr_time_in_zone_1_enabled: false
property int tile_hr_time_in_zone_1_order: 62
property bool tile_hr_time_in_zone_2_enabled: false
property int tile_hr_time_in_zone_2_order: 63
property bool tile_hr_time_in_zone_3_enabled: false
property int tile_hr_time_in_zone_3_order: 64
property bool tile_hr_time_in_zone_4_enabled: false
property int tile_hr_time_in_zone_4_order: 65
property bool tile_hr_time_in_zone_5_enabled: false
property int tile_hr_time_in_zone_5_order: 66
}
@@ -4782,230 +4771,5 @@ ScrollView {
Layout.fillWidth: true
color: Material.color(Material.Lime)
}
AccordionCheckElement {
id: hrTimeInZone1EnabledAccordion
title: qsTr("Heart Rate Time in Zone 1+")
linkedBoolSetting: "tile_hr_time_in_zone_1_enabled"
settings: settings
accordionContent: RowLayout {
spacing: 10
Label {
id: labelHrTimeInZone1Order
text: qsTr("order index:")
Layout.fillWidth: true
horizontalAlignment: Text.AlignRight
}
ComboBox {
id: hrTimeInZone1OrderTextField
model: rootItem.tile_order
displayText: settings.tile_hr_time_in_zone_1_order
Layout.fillHeight: false
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
onActivated: {
displayText = hrTimeInZone1OrderTextField.currentValue
}
}
Button {
id: okHrTimeInZone1OrderButton
text: "OK"
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
onClicked: {settings.tile_hr_time_in_zone_1_order = hrTimeInZone1OrderTextField.displayText; toast.show("Setting saved!"); }
}
}
}
Label {
text: qsTr("Displays total time spent in heart rate Zone 1 or higher during the session.")
font.bold: true
font.italic: true
font.pixelSize: Qt.application.font.pixelSize - 2
textFormat: Text.PlainText
wrapMode: Text.WordWrap
verticalAlignment: Text.AlignVCenter
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
Layout.fillWidth: true
color: Material.color(Material.Lime)
}
AccordionCheckElement {
id: hrTimeInZone2EnabledAccordion
title: qsTr("Heart Rate Time in Zone 2+")
linkedBoolSetting: "tile_hr_time_in_zone_2_enabled"
settings: settings
accordionContent: RowLayout {
spacing: 10
Label {
id: labelHrTimeInZone2Order
text: qsTr("order index:")
Layout.fillWidth: true
horizontalAlignment: Text.AlignRight
}
ComboBox {
id: hrTimeInZone2OrderTextField
model: rootItem.tile_order
displayText: settings.tile_hr_time_in_zone_2_order
Layout.fillHeight: false
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
onActivated: {
displayText = hrTimeInZone2OrderTextField.currentValue
}
}
Button {
id: okHrTimeInZone2OrderButton
text: "OK"
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
onClicked: {settings.tile_hr_time_in_zone_2_order = hrTimeInZone2OrderTextField.displayText; toast.show("Setting saved!"); }
}
}
}
Label {
text: qsTr("Displays total time spent in heart rate Zone 2 or higher during the session.")
font.bold: true
font.italic: true
font.pixelSize: Qt.application.font.pixelSize - 2
textFormat: Text.PlainText
wrapMode: Text.WordWrap
verticalAlignment: Text.AlignVCenter
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
Layout.fillWidth: true
color: Material.color(Material.Lime)
}
AccordionCheckElement {
id: hrTimeInZone3EnabledAccordion
title: qsTr("Heart Rate Time in Zone 3+")
linkedBoolSetting: "tile_hr_time_in_zone_3_enabled"
settings: settings
accordionContent: RowLayout {
spacing: 10
Label {
id: labelHrTimeInZone3Order
text: qsTr("order index:")
Layout.fillWidth: true
horizontalAlignment: Text.AlignRight
}
ComboBox {
id: hrTimeInZone3OrderTextField
model: rootItem.tile_order
displayText: settings.tile_hr_time_in_zone_3_order
Layout.fillHeight: false
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
onActivated: {
displayText = hrTimeInZone3OrderTextField.currentValue
}
}
Button {
id: okHrTimeInZone3OrderButton
text: "OK"
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
onClicked: {settings.tile_hr_time_in_zone_3_order = hrTimeInZone3OrderTextField.displayText; toast.show("Setting saved!"); }
}
}
}
Label {
text: qsTr("Displays total time spent in heart rate Zone 3 or higher during the session.")
font.bold: true
font.italic: true
font.pixelSize: Qt.application.font.pixelSize - 2
textFormat: Text.PlainText
wrapMode: Text.WordWrap
verticalAlignment: Text.AlignVCenter
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
Layout.fillWidth: true
color: Material.color(Material.Lime)
}
AccordionCheckElement {
id: hrTimeInZone4EnabledAccordion
title: qsTr("Heart Rate Time in Zone 4+")
linkedBoolSetting: "tile_hr_time_in_zone_4_enabled"
settings: settings
accordionContent: RowLayout {
spacing: 10
Label {
id: labelHrTimeInZone4Order
text: qsTr("order index:")
Layout.fillWidth: true
horizontalAlignment: Text.AlignRight
}
ComboBox {
id: hrTimeInZone4OrderTextField
model: rootItem.tile_order
displayText: settings.tile_hr_time_in_zone_4_order
Layout.fillHeight: false
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
onActivated: {
displayText = hrTimeInZone4OrderTextField.currentValue
}
}
Button {
id: okHrTimeInZone4OrderButton
text: "OK"
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
onClicked: {settings.tile_hr_time_in_zone_4_order = hrTimeInZone4OrderTextField.displayText; toast.show("Setting saved!"); }
}
}
}
Label {
text: qsTr("Displays total time spent in heart rate Zone 4 or higher during the session.")
font.bold: true
font.italic: true
font.pixelSize: Qt.application.font.pixelSize - 2
textFormat: Text.PlainText
wrapMode: Text.WordWrap
verticalAlignment: Text.AlignVCenter
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
Layout.fillWidth: true
color: Material.color(Material.Lime)
}
AccordionCheckElement {
id: hrTimeInZone5EnabledAccordion
title: qsTr("Heart Rate Time in Zone 5+")
linkedBoolSetting: "tile_hr_time_in_zone_5_enabled"
settings: settings
accordionContent: RowLayout {
spacing: 10
Label {
id: labelHrTimeInZone5Order
text: qsTr("order index:")
Layout.fillWidth: true
horizontalAlignment: Text.AlignRight
}
ComboBox {
id: hrTimeInZone5OrderTextField
model: rootItem.tile_order
displayText: settings.tile_hr_time_in_zone_5_order
Layout.fillHeight: false
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
onActivated: {
displayText = hrTimeInZone5OrderTextField.currentValue
}
}
Button {
id: okHrTimeInZone5OrderButton
text: "OK"
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
onClicked: {settings.tile_hr_time_in_zone_5_order = hrTimeInZone5OrderTextField.displayText; toast.show("Setting saved!"); }
}
}
}
Label {
text: qsTr("Displays total time spent in heart rate Zone 5 or higher during the session.")
font.bold: true
font.italic: true
font.pixelSize: Qt.application.font.pixelSize - 2
textFormat: Text.PlainText
wrapMode: Text.WordWrap
verticalAlignment: Text.AlignVCenter
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
Layout.fillWidth: true
color: Material.color(Material.Lime)
}
}
}

View File

@@ -1111,22 +1111,7 @@ import Qt.labs.platform 1.1
// 2.18.20
property bool domyos_elliptical_fmts: false
property bool proform_xbike: false
property bool proform_225_csx_PFEX32925_INT_0: false
property string peloton_current_user_id: ""
// 2.18.22
property bool trainprogram_pid_ignore_inclination: false
property bool tile_hr_time_in_zone_1_enabled: false
property int tile_hr_time_in_zone_1_order: 62
property bool tile_hr_time_in_zone_2_enabled: false
property int tile_hr_time_in_zone_2_order: 63
property bool tile_hr_time_in_zone_3_enabled: false
property int tile_hr_time_in_zone_3_order: 64
property bool tile_hr_time_in_zone_4_enabled: false
property int tile_hr_time_in_zone_4_order: 65
property bool tile_hr_time_in_zone_5_enabled: false
property int tile_hr_time_in_zone_5_order: 66
property bool proform_xbike: false
}
function paddingZeros(text, limit) {
@@ -3375,8 +3360,7 @@ import Qt.labs.platform 1.1
"Proform SB",
"Nordictrack GX 4.4 Pro",
"TDF 1.0 PFEVEX71316.0",
"Proform XBike",
"Proform 225 CSX PFEX32925 INT.0"
"Proform XBike"
]
// Initialize when the accordion content becomes visible
@@ -3410,8 +3394,7 @@ import Qt.labs.platform 1.1
settings.proform_bike_sb ? 14 :
settings.nordictrack_gx_44_pro ? 15 :
settings.proform_bike_PFEVEX71316_0 ? 16 :
settings.proform_xbike ? 17 :
settings.proform_225_csx_PFEX32925_INT_0 ? 18 : 0;
settings.proform_xbike ? 17 : 0;
console.log("bikeModelComboBox selected model: " + selectedModel);
if (selectedModel >= 0) {
@@ -3443,7 +3426,6 @@ import Qt.labs.platform 1.1
settings.nordictrack_gx_44_pro = false;
settings.proform_bike_PFEVEX71316_0 = false;
settings.proform_xbike = false;
settings.proform_225_csx_PFEX32925_INT_0 = false;
// Set corresponding setting for selected model
switch (currentIndex) {
@@ -3464,7 +3446,6 @@ import Qt.labs.platform 1.1
case 15: settings.nordictrack_gx_44_pro = true; break;
case 16: settings.proform_bike_PFEVEX71316_0 = true; break;
case 17: settings.proform_xbike = true; break;
case 18: settings.proform_225_csx_PFEX32925_INT_0 = true; break;
}
window.settings_restart_to_apply = true;
@@ -5580,33 +5561,6 @@ import Qt.labs.platform 1.1
color: Material.color(Material.Lime)
}
IndicatorOnlySwitch {
text: qsTr("PID Ignore Inclination")
spacing: 0
bottomPadding: 0
topPadding: 0
rightPadding: 0
leftPadding: 0
clip: false
checked: settings.trainprogram_pid_ignore_inclination
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
Layout.fillWidth: true
onClicked: settings.trainprogram_pid_ignore_inclination = checked
}
Label {
text: qsTr("Enabling this the PID will ignore the inclination changes. Default: Disabled.")
font.bold: true
font.italic: true
font.pixelSize: Qt.application.font.pixelSize - 2
textFormat: Text.PlainText
wrapMode: Text.WordWrap
verticalAlignment: Text.AlignVCenter
Layout.alignment: Qt.AlignLeft | Qt.AlignTop
Layout.fillWidth: true
color: Material.color(Material.Lime)
}
RowLayout {
spacing: 10
Label {
@@ -11652,23 +11606,11 @@ import Qt.labs.platform 1.1
color: Material.color(Material.Lime)
}
RowLayout {
Layout.fillWidth: true
Button {
id: clearLogs
text: "Clear History"
Layout.alignment: Qt.AlignLeft | Qt.AlignVCenter
onClicked: rootItem.clearFiles();
}
Button {
text: "Show Logs Folder"
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
onClicked: {
toast.show(rootItem.getProfileDir())
}
}
Button {
id: clearLogs
text: "Clear History"
Layout.alignment: Qt.AlignRight | Qt.AlignVCenter
onClicked: rootItem.clearFiles();
}
Label {

View File

@@ -586,6 +586,17 @@ void trainprogram::scheduler() {
QMutexLocker(&this->schedulerMutex);
QSettings settings;
QDateTime now = QDateTime::currentDateTime();
qint64 msecsElapsed = lastSchedulerCall.msecsTo(now);
// Reset jitter if it's getting too large
if (qAbs(currentTimerJitter) > 5000) {
currentTimerJitter = 0;
}
currentTimerJitter += msecsElapsed - 1000;
lastSchedulerCall = now;
// outside the if case about a valid train program because the information for the floating window url should be
// sent anyway
if (settings.value(QZSettings::peloton_companion_workout_ocr, QZSettings::default_companion_peloton_workout_ocr)
@@ -811,6 +822,7 @@ void trainprogram::scheduler() {
#endif
}
currentTimerJitter = 0;
return;
}
@@ -832,6 +844,20 @@ void trainprogram::scheduler() {
#endif
ticks++;
qDebug() << QStringLiteral("trainprogram ticks") << ticks << QStringLiteral("currentTimerJitter") << currentTimerJitter;
if(qAbs(currentTimerJitter) > 1000) {
// we are late...
if (currentTimerJitter > 1000) {
int seconds = currentTimerJitter / 1000;
ticks += seconds;
currentTimerJitter -= (seconds * 1000);
qDebug() << QStringLiteral("fixing jitter!") << seconds << ticks << currentTimerJitter;
} else {
// negative jitter, reset the counter without touching the ticks
currentTimerJitter = 0;
}
}
double odometerFromTheDevice = bluetoothManager->device()->odometer();
@@ -1270,6 +1296,7 @@ void trainprogram::restart() {
ticks = 0;
offset = 0;
currentStep = 0;
currentTimerJitter = 0;
started = true;
}

View File

@@ -168,6 +168,9 @@ private slots:
int lastStepTimestampChanged = 0;
double lastCurrentStepDistance = 0.0;
QTime lastCurrentStepTime = QTime(0, 0, 0);
int64_t currentTimerJitter = 0;
QDateTime lastSchedulerCall = QDateTime::currentDateTime();
QUdpSocket* pelotonOCRsocket = nullptr;
void pelotonOCRcomputeTime(QString t);