Compare commits

...

47 Commits

Author SHA1 Message Date
Roberto Viola
482b136203 Merge branch 'master' into treadmill-gpio 2025-07-10 09:12:42 +02:00
Roberto Viola
e91faf273d merge 2025-03-20 09:53:00 +00:00
Roberto Viola
5c00f3d11a Update bluetooth.cpp 2024-11-15 10:33:17 +01:00
Roberto Viola
1be1f6fc8c Update qdomyos-zwift-tests.pro 2024-11-13 15:45:25 +01:00
Roberto Viola
ed0b112a00 Update main.yml 2024-11-13 12:26:44 +01:00
Roberto Viola
cb4217319d Update main.yml 2024-11-13 12:11:52 +01:00
Roberto Viola
5ac41ec1aa Update main.yml 2024-11-13 11:38:38 +01:00
Roberto Viola
9c6f87804a Update main.yml 2024-11-13 11:16:15 +01:00
Roberto Viola
80bae7db76 Update main.yml 2024-11-13 09:45:15 +01:00
Roberto Viola
cd7365d47e Revert "Update main.yml"
This reverts commit a793f17dfb.
2024-11-13 09:40:54 +01:00
Roberto Viola
a793f17dfb Update main.yml 2024-11-13 09:36:08 +01:00
Roberto Viola
cbb2c8f35d Merge branch 'master' into treadmill-gpio 2024-11-13 09:33:55 +01:00
Roberto Viola
6481ef7ae9 Update gpiotreadmill.cpp 2024-11-13 09:19:59 +01:00
Roberto Viola
d6cf6773e5 Update gpiotreadmill.cpp 2024-11-13 09:09:17 +01:00
Roberto Viola
eadb17bd44 Update gpiotreadmill.h 2024-11-13 08:59:23 +01:00
Roberto Viola
cc80306337 merging 2024-11-13 08:39:48 +01:00
Roberto Viola
e1b05612a7 Merge branch 'master' into treadmill-gpio 2024-11-13 08:36:44 +01:00
Roberto Viola
d9034eff3f Local input for headless mode #938
https://github.com/cagnulein/qdomyos-zwift/issues/938#issuecomment-1256805749
2022-09-26 11:53:00 +02:00
Roberto Viola
94f5c37667 disabling qml too if the no-gui selector is enabled 2022-09-19 08:44:19 +02:00
Roberto Viola
c9b10026e0 workaround 2022-09-17 18:11:34 +02:00
Roberto Viola
d6937433da Local input for headless mode #938 2022-09-16 10:20:53 +02:00
Roberto Viola
6a16672ab1 fixing inclination calls #938 2022-09-15 08:23:42 +02:00
Roberto Viola
daa8dca053 Update main.cpp 2022-09-13 20:00:39 +02:00
Roberto Viola
21349a6e06 Rename consolereader.cpp to ConsoleReader.cpp 2022-09-13 09:34:42 +02:00
Roberto Viola
70dff0b78e Rename consolereader.h to ConsoleReader.h 2022-09-13 09:34:21 +02:00
Roberto Viola
7d88f9b211 Merge branch 'treadmill-gpio' of https://github.com/cagnulein/qdomyos-zwift into treadmill-gpio 2022-09-12 16:36:10 +02:00
Roberto Viola
7a58c776f9 Local input for headless mode #938 2022-09-12 16:35:52 +02:00
Roberto Viola
4f3051671e Merge branch 'master' into treadmill-gpio 2022-09-12 16:31:11 +02:00
Roberto Viola
ad4514a7e3 Local input for headless mode #938 2022-09-12 16:29:14 +02:00
Roberto Viola
f8f8e6c7ba Local input for headless mode #938 2022-09-12 16:28:08 +02:00
Roberto Viola
f195432020 Update bluetooth.cpp 2022-07-28 09:29:42 +02:00
Roberto Viola
283c1015f2 Merge branch 'master' into treadmill-gpio 2022-07-27 10:52:05 +02:00
Roberto Viola
8f41a2c8d8 added connectedAndDiscovered(); to gpiotreadmill
#525
2022-07-27 10:49:51 +02:00
Roberto Viola
6aacfe3cb0 Merge pull request #627 from december-soul/treadmill-gpio 2022-01-27 20:02:51 +01:00
decembersoul
477f58cf03 use semaphore to avoid press simultaneously the buttons 2022-01-27 19:13:00 +01:00
decembersoul
9d2ef5822d Merge branch 'treadmill-gpio' of https://github.com/december-soul/qdomyos-zwift into treadmill-gpio 2022-01-25 14:31:39 +01:00
decembersoul
8a56aab0ce add descructor to clean up thread 2022-01-25 14:26:18 +01:00
decembersoul
5e93ea947d Merge branch 'cagnulein:treadmill-gpio' into treadmill-gpio 2022-01-25 13:35:18 +01:00
decembersoul
8539fe91ea move GPIO worker into thread 2022-01-25 13:29:01 +01:00
Roberto Viola
4e81c60370 Merge pull request #587 from december-soul/treadmill-gpio 2022-01-16 18:32:04 +01:00
patrick
5aaa37ee02 Improve the setting of the speed and the slope 2022-01-16 18:08:04 +01:00
Roberto Viola
0aa1284898 fix gpio delay #525 2022-01-14 10:42:53 +01:00
Roberto Viola
d7e6cf51e9 fix build issue #525 2022-01-14 10:19:10 +01:00
Roberto Viola
ab8fe4f4a6 fix build issue #525 2022-01-14 09:58:59 +01:00
Roberto Viola
5c344a5a98 fixed zwift interface on gpiotreadmill 2022-01-13 19:41:57 +01:00
Roberto Viola
963becad7c first very raw release #525 2022-01-11 14:41:22 +01:00
Roberto Viola
5dd9547121 starting to create the gpio module 2022-01-05 23:52:49 +01:00
10 changed files with 623 additions and 4 deletions

View File

@@ -1266,8 +1266,20 @@ jobs:
args: >
bash -c "
set -ex &&
apt-get update &&
apt-get install -y build-essential git cmake qtbase5-dev qtbase5-private-dev qtchooser qt5-qmake qtbase5-dev-tools qttools5-dev-tools libqt5svg5-dev qtmultimedia5-dev libqt5charts5-dev qtpositioning5-dev qtconnectivity5-dev libqt5websockets5-dev libqt5texttospeech5-dev libqt5bluetooth5 libqt5networkauth5-dev qml-module-qtlocation qml-module-qtpositioning qtlocation5-dev libqt5quickcontrols2-5 qtquickcontrols2-5-dev qml-module-qtquick-controls2 &&
apt-get update &&
apt-get install -y build-essential git cmake wget
qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools qttools5-dev-tools
libqt5svg5-dev qtmultimedia5-dev libqt5charts5-dev qtpositioning5-dev
qtconnectivity5-dev libqt5websockets5-dev libqt5texttospeech5-dev
libqt5bluetooth5 libqt5networkauth5-dev qml-module-qtlocation gettext-base
qml-module-qtpositioning qtlocation5-dev libqt5quickcontrols2-5
qtquickcontrols2-5-dev qml-module-qtquick-controls2 &&
cd /tmp &&
git clone https://github.com/WiringPi/WiringPi.git &&
cd WiringPi &&
./build debian &&
mv debian-template/wiringpi_3.10_armhf.deb . &&
apt install -y ./wiringpi_3.10_armhf.deb &&
export QT_SELECT=qt5 &&
export PATH=/usr/lib/qt5/bin:$PATH &&
cd /github/workspace &&
@@ -1325,8 +1337,20 @@ jobs:
args: >
bash -c "
set -ex &&
apt-get update &&
apt-get install -y build-essential git cmake qtbase5-dev qtbase5-private-dev qtchooser qt5-qmake qtbase5-dev-tools qttools5-dev-tools libqt5svg5-dev qtmultimedia5-dev libqt5charts5-dev qtpositioning5-dev qtconnectivity5-dev libqt5websockets5-dev libqt5texttospeech5-dev libqt5bluetooth5 libqt5networkauth5-dev qml-module-qtlocation qml-module-qtpositioning qtlocation5-dev libqt5quickcontrols2-5 qtquickcontrols2-5-dev qml-module-qtquick-controls2 &&
apt-get update &&
apt-get install -y build-essential git cmake wget
qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools qttools5-dev-tools
libqt5svg5-dev qtmultimedia5-dev libqt5charts5-dev qtpositioning5-dev
qtconnectivity5-dev libqt5websockets5-dev libqt5texttospeech5-dev
libqt5bluetooth5 libqt5networkauth5-dev qml-module-qtlocation
qml-module-qtpositioning qtlocation5-dev libqt5quickcontrols2-5 gettext-base
qtquickcontrols2-5-dev qml-module-qtquick-controls2 &&
cd /tmp &&
git clone https://github.com/WiringPi/WiringPi.git &&
cd WiringPi &&
./build debian &&
mv debian-template/wiringpi_3.10_arm64.deb . &&
apt install -y ./wiringpi_3.10_arm64.deb &&
export QT_SELECT=qt5 &&
export PATH=/usr/lib/qt5/bin:$PATH &&
cd /github/workspace &&

89
src/ConsoleReader.cpp Normal file
View File

@@ -0,0 +1,89 @@
//#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

21
src/ConsoleReader.h Normal file
View File

@@ -0,0 +1,21 @@
#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

@@ -450,6 +450,7 @@ 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 = true; // TO FIX!! settings.value(QStringLiteral("gpio_treadmill"), false).toBool();
bool fake_bike =
settings.value(QZSettings::applewatch_fakedevice, QZSettings::default_applewatch_fakedevice).toBool();
bool fakedevice_elliptical =
@@ -686,6 +687,20 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device) {
emit searchingStop();
}
this->signalBluetoothDeviceConnected(fakeBike);
} else if (gpio_treadmill && !gpioTreadmill) {
discoveryAgent->stop();
gpioTreadmill = new gpiotreadmill(noWriteResistance, noHeartService);
emit deviceConnected(b);
connect(gpioTreadmill, &bluetoothdevice::connectedAndDiscovered, this,
&bluetooth::connectedAndDiscovered);
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);
} else if (fakedevice_elliptical && !fakeElliptical) {
this->stopDiscovery();
fakeElliptical = new fakeelliptical(noWriteResistance, noHeartService, false);
@@ -3347,6 +3362,11 @@ void bluetooth::restart() {
delete fakeBike;
fakeBike = nullptr;
}
if (gpioTreadmill) {
delete gpioTreadmill;
gpioTreadmill = nullptr;
}
if (fakeElliptical) {
delete fakeElliptical;
@@ -3816,6 +3836,8 @@ bluetoothdevice *bluetooth::device() {
return powerTreadmill;
} else if (fakeBike) {
return fakeBike;
} else if (gpioTreadmill) {
return gpioTreadmill;
} else if (fakeElliptical) {
return fakeElliptical;
} else if (fakeRower) {

View File

@@ -20,6 +20,8 @@
#include "devices/discoveryoptions.h"
#include "qzsettings.h"
#include "gpiotreadmill.h"
#include "devices/activiotreadmill/activiotreadmill.h"
#include "devices/speraxtreadmill/speraxtreadmill.h"
#include "devices/antbike/antbike.h"
@@ -223,6 +225,7 @@ class bluetooth : public QObject, public SignalHandler {
nordictrackifitadbbike *nordictrackifitadbBike = nullptr;
nordictrackifitadbelliptical *nordictrackifitadbElliptical = nullptr;
octaneelliptical *octaneElliptical = nullptr;
gpiotreadmill *gpioTreadmill = nullptr;
octanetreadmill *octaneTreadmill = nullptr;
pelotonbike *pelotonBike = nullptr;
proformrower *proformRower = nullptr;

316
src/gpiotreadmill.cpp Normal file
View File

@@ -0,0 +1,316 @@
#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 1
#ifdef Q_OS_RASPI
#include <wiringPi.h>
#else
#define OUTPUT 1
void digitalWrite(int pin, int state) {
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}, pinUp{pinUp}, pinDown{pinDown}, step{step}, currentValue{currentValue}, semaphore{semaphore}
{
pinMode(pinUp, OUTPUT);
pinMode(pinDown, OUTPUT);
digitalWrite(pinUp, 0);
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();
digitalWrite(pinUp, 1);
QThread::msleep(GPIO_KEEP_MS);
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();
digitalWrite(pinDown, 1);
QThread::msleep(GPIO_KEEP_MS);
digitalWrite(pinDown, 0);
QThread::msleep(GPIO_REBOUND_MS);
semaphore->release();
currentValue -= step;
if(QThread::currentThread()->isInterruptionRequested()) {
qDebug() << "Interrupting set " + name;
return;
}
}
}
}
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);
}
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);
}
gpiotreadmill::~gpiotreadmill() {
speedThread->requestInterruption();
speedThread->quit();
speedThread->wait();
delete speedThread;
inclineThread->requestInterruption();
inclineThread->quit();
inclineThread->wait();
delete inclineThread;
delete semaphore;
}
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) {
debug("creating virtual treadmill interface...");
virtualTreadMill = new virtualtreadmill(this, noHeartService);
connect(virtualTreadMill, &virtualtreadmill::debug, this, &gpiotreadmill::debug);
connect(virtualTreadMill, &virtualtreadmill::changeInclination, this,
&gpiotreadmill::changeInclinationRequested);
} else {
debug("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;
debug("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();
}
emit debug(QStringLiteral("Current speed: ") + QString::number(Speed.value()));
emit debug(QStringLiteral("Current incline: ") + QString::number(Inclination.value()));
emit debug(QStringLiteral("Current heart: ") + QString::number(Heart.value()));
emit debug(QStringLiteral("Current KCal: ") + QString::number(KCal.value()));
emit debug(QStringLiteral("Current KCal from the machine: ") + QString::number(KCal.value()));
emit debug(QStringLiteral("Current Distance: ") + QString::number(Distance.value()));
emit debug(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) {
emit debug(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) {
emit debug(QStringLiteral("writing incline ") + QString::number(requestInclination));
forceIncline(requestInclination);
}
requestInclination = -1;
}
if (requestStart != -1) {
emit debug(QStringLiteral("starting..."));
if (lastSpeed == 0.0) {
lastSpeed = 0.5;
}
digitalWrite(OUTPUT_START, 1);
QThread::msleep(GPIO_KEEP_MS);
digitalWrite(OUTPUT_START, 0);
requestStart = -1;
emit tapeStarted();
}
if (requestStop != -1) {
emit debug(QStringLiteral("stopping..."));
digitalWrite(OUTPUT_STOP, 1);
QThread::msleep(GPIO_KEEP_MS);
digitalWrite(OUTPUT_STOP, 0);
requestStop = -1;
}
if (requestFanSpeed != -1) {
emit debug(QStringLiteral("changing fan speed..."));
requestFanSpeed = -1;
}
if (requestIncreaseFan != -1) {
emit debug(QStringLiteral("increasing fan speed..."));
requestIncreaseFan = -1;
} else if (requestDecreaseFan != -1) {
emit debug(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; }

127
src/gpiotreadmill.h Normal file
View File

@@ -0,0 +1,127 @@
#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 "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 = 275;
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();
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 = 23;
const uint8_t OUTPUT_STOP = 25;
const uint16_t GPIO_KEEP_MS = 275;
//const uint16_t GPIO_REBOUND_MS = 200;
const double SPEED_STEP = 0.1;
const double INCLINATION_STEP = 0.5;
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 update();
};
#endif // GPIOTREADMILL_H

View File

@@ -4,6 +4,7 @@
#include <stdlib.h>
#ifdef Q_OS_LINUX
#ifndef Q_OS_ANDROID
#include "ConsoleReader.h"
#include <unistd.h> // getuid
#include "EventHandler.h"
#endif
@@ -73,6 +74,7 @@ bool run_cadence_sensor = false;
bool horizon_treadmill_7_8 = false;
bool horizon_treadmill_force_ftms = false;
bool nordictrack_10_treadmill = false;
bool gpiotreadmill = false;
bool proform_performance_300i_treadmill = false;
bool reebok_fr30_treadmill = false;
bool zwift_play = false;
@@ -292,6 +294,8 @@ 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], "-proform-perf-300i-treadmill"))
proform_performance_300i_treadmill = true;
if (!qstrcmp(argv[i], "-reebok_fr30_treadmill"))
@@ -572,6 +576,7 @@ int main(int argc, char *argv[]) {
}
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS)
else {
settings.setValue(QStringLiteral("gpio_treadmill"), gpiotreadmill);
settings.setValue(QZSettings::miles_unit, miles);
settings.setValue(QZSettings::bluetooth_no_reconnection, bluetooth_no_reconnection);
settings.setValue(QZSettings::bluetooth_relaxed, bluetooth_relaxed);
@@ -848,6 +853,11 @@ int main(int argc, char *argv[]) {
}
#endif
#ifdef Q_OS_LINUX
ConsoleReader *consoleReader = new ConsoleReader(&bl);
consoleReader->start();
#endif
#if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS)
if (qobject_cast<QApplication *>(app.data())) {
// start GUI version...

View File

@@ -2,6 +2,7 @@ include(../defaults.pri)
QT += bluetooth widgets xml positioning quick networkauth websockets texttospeech location multimedia
QTPLUGIN += qavfmediaplayer
QT+= charts core-private
LIBS += -lwiringPi
qtHaveModule(httpserver) {
QT += httpserver
@@ -156,6 +157,8 @@ characteristics/characteristicnotifier2a5b.cpp \
characteristics/characteristicnotifier2acc.cpp \
characteristics/characteristicnotifier2acd.cpp \
characteristics/characteristicnotifier2ad9.cpp \
ConsoleReader.cpp \
gpiotreadmill.cpp \
characteristics/characteristicwriteprocessor.cpp \
characteristics/characteristicwriteprocessore005.cpp \
devices/computrainerbike/computrainerbike.cpp \
@@ -453,6 +456,8 @@ characteristics/characteristicnotifier2ad9.h \
characteristics/characteristicwriteprocessore005.h \
devices/computrainerbike/computrainerbike.h \
definitions.h \
ConsoleReader.h \
gpiotreadmill.h \
devices/fakeelliptical/fakeelliptical.h \
devices/faketreadmill/faketreadmill.h \
devices/lifefitnesstreadmill/lifefitnesstreadmill.h \

View File

@@ -33,6 +33,8 @@ win32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../src/release/ -lqdom
else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../src/debug/ -lqdomyos-zwift
else:unix: LIBS += -L$$OUT_PWD/../src/ -lqdomyos-zwift
LIBS += -lwiringPi
INCLUDEPATH += $$PWD/../src $$PWD/../src/devices
DEPENDPATH += $$PWD/../src $$PWD/../src/devices