mirror of
https://github.com/cagnulein/qdomyos-zwift.git
synced 2026-02-18 00:17:41 +01:00
Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
19c3a90bf4 | ||
|
|
705baaa37c | ||
|
|
e302e90066 | ||
|
|
9d9800d4e6 | ||
|
|
5c00a959f4 | ||
|
|
54501760d3 | ||
|
|
2f4b76014f | ||
|
|
7de4bac932 | ||
|
|
d992959792 | ||
|
|
1ce77629ff | ||
|
|
908c1536f6 | ||
|
|
b8948c6d8f | ||
|
|
1ab448f7cc | ||
|
|
38ea3f5c80 | ||
|
|
a87e818d9a | ||
|
|
d852bd44fe | ||
|
|
5f7d7e01b8 | ||
|
|
548fa9d8d6 | ||
|
|
3a725d71b5 | ||
|
|
a304963dc5 | ||
|
|
bf9fb4537b | ||
|
|
838fe8c96e | ||
|
|
77b204d9fd | ||
|
|
8a6e8e9c9d | ||
|
|
123df9db6b |
74
.github/workflows/main.yml
vendored
74
.github/workflows/main.yml
vendored
@@ -19,19 +19,19 @@ jobs:
|
||||
|
||||
# Steps represent a sequence of tasks that will be executed as part of the job
|
||||
steps:
|
||||
- name: Cache Qt Linux Desktop
|
||||
id: cache-qt-linux-desktop
|
||||
uses: actions/cache@v1
|
||||
with:
|
||||
path: '${{ github.workspace }}/output/linux-desktop/'
|
||||
key: ${{ runner.os }}-QtCache-Linux-Desktop
|
||||
# - name: Cache Qt Linux Desktop
|
||||
# id: cache-qt-linux-desktop
|
||||
# uses: actions/cache@v1
|
||||
# with:
|
||||
# path: '${{ github.workspace }}/output/linux-desktop/'
|
||||
# key: ${{ runner.os }}-QtCache-Linux-Desktop
|
||||
|
||||
- name: Cache Qt Linux Android
|
||||
id: cache-qt-android
|
||||
uses: actions/cache@v1
|
||||
with:
|
||||
path: '${{ github.workspace }}/output/android/'
|
||||
key: ${{ runner.os }}-QtCache-Android
|
||||
# - name: Cache Qt Linux Android
|
||||
# id: cache-qt-android
|
||||
# uses: actions/cache@v1
|
||||
# with:
|
||||
# path: '${{ github.workspace }}/output/android/'
|
||||
# key: ${{ runner.os }}-QtCache-Android
|
||||
|
||||
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
|
||||
- uses: actions/checkout@v2
|
||||
@@ -45,7 +45,7 @@ jobs:
|
||||
target: 'desktop'
|
||||
modules: 'qtcharts debug_info'
|
||||
dir: '${{ github.workspace }}/output/linux-desktop/'
|
||||
cached: ${{ steps.cache-qt-linux-desktop.outputs.cache-hit }}
|
||||
# cached: ${{ steps.cache-qt-linux-desktop.outputs.cache-hit }}
|
||||
|
||||
- name: Compile Linux Desktop
|
||||
run: cd src; qmake; make -j4
|
||||
@@ -56,39 +56,39 @@ jobs:
|
||||
name: linux-desktop-binary
|
||||
path: src/qdomyos-zwift
|
||||
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
repository: nttld/setup-ndk
|
||||
path: setup-ndk
|
||||
# - uses: actions/checkout@v2
|
||||
# with:
|
||||
# repository: nttld/setup-ndk
|
||||
# path: setup-ndk
|
||||
# The packages.json in nttld/setup-ndk has already been updated,
|
||||
# https://github.com/nttld/setup-ndk/commit/831db5b02a0f0cab80614619efe461a3dcc140e6
|
||||
# but `dist/*` has not been rebuilt yet. Build it.
|
||||
# https://github.com/nttld/setup-ndk/tree/main/dist
|
||||
- name: Locally rebuilt setup-ndk
|
||||
run: |
|
||||
npm -prefix ./setup-ndk install
|
||||
npm -prefix ./setup-ndk run all
|
||||
# - name: Locally rebuilt setup-ndk
|
||||
# run: |
|
||||
# npm -prefix ./setup-ndk install
|
||||
# npm -prefix ./setup-ndk run all
|
||||
# Install using locally rebuilt setup-ndk
|
||||
- name: Setup Android NDK r21d
|
||||
uses: ./setup-ndk
|
||||
# - name: Setup Android NDK r21d
|
||||
# uses: ./setup-ndk
|
||||
#- uses: nttld/setup-ndk@v1
|
||||
with:
|
||||
ndk-version: r21d
|
||||
# with:
|
||||
# ndk-version: r21d
|
||||
|
||||
# waiting github.com/jurplel/install-qt-action/issues/63
|
||||
- name: Install Qt Android
|
||||
uses: jurplel/install-qt-action@v2
|
||||
with:
|
||||
version: '5.12.9'
|
||||
host: 'linux'
|
||||
target: 'android'
|
||||
arch: 'android_armv7'
|
||||
modules: 'qtcharts debug_info'
|
||||
dir: '${{ github.workspace }}/output/android/'
|
||||
cached: ${{ steps.cache-qt-android.outputs.cache-hit }}
|
||||
# - name: Install Qt Android
|
||||
# uses: jurplel/install-qt-action@v2
|
||||
# with:
|
||||
# version: '5.12.9'
|
||||
# host: 'linux'
|
||||
# target: 'android'
|
||||
# arch: 'android_armv7'
|
||||
# modules: 'qtcharts debug_info'
|
||||
# dir: '${{ github.workspace }}/output/android/'
|
||||
# cached: ${{ steps.cache-qt-android.outputs.cache-hit }}
|
||||
|
||||
- name: Compile Android
|
||||
run: cd src; qmake; make -j4
|
||||
# - name: Compile Android
|
||||
# run: cd src; qmake; make -j4
|
||||
|
||||
# - name: Install Qt MacOS
|
||||
# uses: jurplel/install-qt-action@v2
|
||||
|
||||
@@ -5,6 +5,8 @@ Zwift bridge for Treadmills and Bike!
|
||||
|
||||

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

|
||||

|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ HomeForm{
|
||||
width: 175
|
||||
height: 125
|
||||
|
||||
visible: visibleItem
|
||||
Component.onCompleted: console.log("completed " + objectName)
|
||||
|
||||
Rectangle {
|
||||
|
||||
@@ -28,19 +28,42 @@ Page {
|
||||
width: 50
|
||||
height: 100
|
||||
color: Material.backgroundColor
|
||||
Image {
|
||||
Column {
|
||||
id: column
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
id: treadmill_connection
|
||||
width: 48
|
||||
height: 48
|
||||
source: "icons/icons/bluetooth-icon.png"
|
||||
enabled: rootItem.device
|
||||
smooth: true
|
||||
}
|
||||
ColorOverlay {
|
||||
anchors.fill: treadmill_connection
|
||||
source: treadmill_connection
|
||||
color: treadmill_connection.enabled ? "#00000000" : "#B0D3d3d3"
|
||||
width: parent.width
|
||||
height: 100
|
||||
spacing: 0
|
||||
padding: 0
|
||||
Rectangle {
|
||||
width: 50
|
||||
height: 100
|
||||
color: Material.backgroundColor
|
||||
|
||||
Image {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
id: treadmill_connection
|
||||
width: 48
|
||||
height: 48
|
||||
source: "icons/icons/bluetooth-icon.png"
|
||||
enabled: rootItem.device
|
||||
smooth: true
|
||||
}
|
||||
ColorOverlay {
|
||||
anchors.fill: treadmill_connection
|
||||
source: treadmill_connection
|
||||
color: treadmill_connection.enabled ? "#00000000" : "#B0D3d3d3"
|
||||
}
|
||||
}
|
||||
Image {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
id: treadmill_signal
|
||||
width: 24
|
||||
height: 24
|
||||
source: rootItem.signal
|
||||
smooth: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,8 +3,9 @@
|
||||
#include <QDateTime>
|
||||
#include <QMetaEnum>
|
||||
#include <QBluetoothLocalDevice>
|
||||
#include <QtXml>
|
||||
|
||||
bluetooth::bluetooth(bool logs, QString deviceName, bool noWriteResistance, bool noHeartService, uint32_t pollDeviceTime, bool noConsole, bool testResistance) : QObject(nullptr)
|
||||
bluetooth::bluetooth(bool logs, QString deviceName, bool noWriteResistance, bool noHeartService, uint32_t pollDeviceTime, bool noConsole, bool testResistance)
|
||||
{
|
||||
QLoggingCategory::setFilterRules(QStringLiteral("qt.bluetooth* = true"));
|
||||
filterDevice = deviceName;
|
||||
@@ -69,11 +70,26 @@ void bluetooth::deviceDiscovered(const QBluetoothDeviceInfo &device)
|
||||
{
|
||||
discoveryAgent->stop();
|
||||
domyos = new domyostreadmill(this->pollDeviceTime, noConsole, noHeartService);
|
||||
stateFileRead();
|
||||
emit(deviceConnected());
|
||||
connect(domyos, SIGNAL(disconnected()), this, SLOT(restart()));
|
||||
connect(domyos, SIGNAL(debug(QString)), this, SLOT(debug(QString)));
|
||||
connect(domyos, SIGNAL(speedChanged(double)), this, SLOT(speedChanged(double)));
|
||||
connect(domyos, SIGNAL(inclinationChanged(double)), this, SLOT(inclinationChanged(double)));
|
||||
domyos->deviceDiscovered(device);
|
||||
}
|
||||
else if(device.name().startsWith("ECH-SPORT") && filter)
|
||||
{
|
||||
discoveryAgent->stop();
|
||||
echelonConnectSport = new echelonconnectsport(noWriteResistance, noHeartService);
|
||||
//stateFileRead();
|
||||
emit(deviceConnected());
|
||||
connect(echelonConnectSport, SIGNAL(disconnected()), this, SLOT(restart()));
|
||||
connect(echelonConnectSport, SIGNAL(debug(QString)), this, SLOT(debug(QString)));
|
||||
//connect(echelonConnectSport, SIGNAL(speedChanged(double)), this, SLOT(speedChanged(double)));
|
||||
//connect(echelonConnectSport, SIGNAL(inclinationChanged(double)), this, SLOT(inclinationChanged(double)));
|
||||
echelonConnectSport->deviceDiscovered(device);
|
||||
}
|
||||
else if((device.name().startsWith("TRX ROUTE KEY")) && filter)
|
||||
{
|
||||
discoveryAgent->stop();
|
||||
@@ -116,6 +132,11 @@ void bluetooth::restart()
|
||||
delete trxappgateusb;
|
||||
trxappgateusb = 0;
|
||||
}
|
||||
if(echelonConnectSport)
|
||||
{
|
||||
delete echelonConnectSport;
|
||||
echelonConnectSport = 0;
|
||||
}
|
||||
discoveryAgent->start();
|
||||
}
|
||||
|
||||
@@ -129,5 +150,104 @@ bluetoothdevice* bluetooth::device()
|
||||
return toorx;
|
||||
else if(trxappgateusb)
|
||||
return trxappgateusb;
|
||||
else if(echelonConnectSport)
|
||||
return echelonConnectSport;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool bluetooth::handleSignal(int signal)
|
||||
{
|
||||
if(signal == SIGNALS::SIG_INT)
|
||||
{
|
||||
qDebug() << "SIGINT";
|
||||
QFile::remove("status.xml");
|
||||
exit(0);
|
||||
}
|
||||
// Let the signal propagate as though we had not been there
|
||||
return false;
|
||||
}
|
||||
|
||||
void bluetooth::stateFileRead()
|
||||
{
|
||||
if(!device()) return;
|
||||
|
||||
QFile* log;
|
||||
QDomDocument xmlBOM;
|
||||
log = new QFile("status.xml");
|
||||
if(!log->open(QIODevice::ReadOnly | QIODevice::Text))
|
||||
{
|
||||
qDebug() << "Open status.xml for writing failed";
|
||||
return;
|
||||
}
|
||||
xmlBOM.setContent(log);
|
||||
QDomElement root=xmlBOM.documentElement();
|
||||
|
||||
// Get root names and attributes
|
||||
QString Type=root.tagName();
|
||||
QString lastUpdated = root.attribute("Updated", QDateTime::currentDateTime().toString());
|
||||
|
||||
QDomElement machine=root.firstChild().toElement();
|
||||
// Loop while there is a child
|
||||
while(!machine.isNull())
|
||||
{
|
||||
// Check if the child tag name is COMPONENT
|
||||
if (machine.tagName()=="Treadmill")
|
||||
{
|
||||
// Read and display the component ID
|
||||
double speed = machine.attribute("Speed", "0.0").toDouble();
|
||||
double inclination = machine.attribute("Incline", "0.0").toDouble();
|
||||
|
||||
((domyostreadmill*)device())->setLastSpeed(speed);
|
||||
((domyostreadmill*)device())->setLastInclination(inclination);
|
||||
}
|
||||
|
||||
// Next component
|
||||
machine = machine.nextSibling().toElement();
|
||||
}
|
||||
|
||||
log->close();
|
||||
}
|
||||
|
||||
void bluetooth::stateFileUpdate()
|
||||
{
|
||||
if(!device()) return;
|
||||
if(device()->deviceType() != bluetoothdevice::TREADMILL) return;
|
||||
|
||||
QFile* log;
|
||||
QDomDocument docStatus;
|
||||
QDomElement docRoot;
|
||||
QDomElement docTreadmill;
|
||||
QDomElement docHeart;
|
||||
log = new QFile("status.xml");
|
||||
if(!log->open(QIODevice::WriteOnly | QIODevice::Text))
|
||||
{
|
||||
qDebug() << "Open status.xml for writing failed";
|
||||
return;
|
||||
}
|
||||
docRoot = docStatus.createElement("Gym");
|
||||
docStatus.appendChild(docRoot);
|
||||
docTreadmill = docStatus.createElement("Treadmill");
|
||||
docTreadmill.setAttribute("Speed", QString::number(device()->currentSpeed(), 'f', 1));
|
||||
docTreadmill.setAttribute("Incline", QString::number(((treadmill*)device())->currentInclination(), 'f', 1));
|
||||
docRoot.appendChild(docTreadmill);
|
||||
//docHeart = docStatus.createElement("Heart");
|
||||
//docHeart.setAttribute("Rate", QString::number(currentHeart));
|
||||
//docRoot.appendChild(docHeart);
|
||||
docRoot.setAttribute("Updated", QDateTime::currentDateTime().toString());
|
||||
QTextStream stream(log);
|
||||
stream << docStatus.toString();
|
||||
log->flush();
|
||||
log->close();
|
||||
}
|
||||
|
||||
void bluetooth::speedChanged(double speed)
|
||||
{
|
||||
Q_UNUSED(speed);
|
||||
stateFileUpdate();
|
||||
}
|
||||
|
||||
void bluetooth::inclinationChanged(double inclination)
|
||||
{
|
||||
Q_UNUSED(inclination);
|
||||
stateFileUpdate();
|
||||
}
|
||||
|
||||
@@ -20,9 +20,11 @@
|
||||
#include "domyosbike.h"
|
||||
#include "trxappgateusbtreadmill.h"
|
||||
#include "toorxtreadmill.h"
|
||||
#include "echelonconnectsport.h"
|
||||
#include "bluetoothdevice.h"
|
||||
#include "signalhandler.h"
|
||||
|
||||
class bluetooth : public QObject
|
||||
class bluetooth : public QObject, public SignalHandler
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
@@ -36,6 +38,7 @@ private:
|
||||
domyosbike* domyosBike = 0;
|
||||
toorxtreadmill* toorx = 0;
|
||||
trxappgateusbtreadmill* trxappgateusb = 0;
|
||||
echelonconnectsport* echelonConnectSport = 0;
|
||||
QString filterDevice = "";
|
||||
bool testResistance = false;
|
||||
bool noWriteResistance = false;
|
||||
@@ -44,6 +47,10 @@ private:
|
||||
bool logs = true;
|
||||
uint32_t pollDeviceTime = 200;
|
||||
|
||||
bool handleSignal(int signal);
|
||||
void stateFileUpdate();
|
||||
void stateFileRead();
|
||||
|
||||
signals:
|
||||
void deviceConnected();
|
||||
void deviceFound(QString name);
|
||||
@@ -54,6 +61,8 @@ public slots:
|
||||
|
||||
private slots:
|
||||
void deviceDiscovered(const QBluetoothDeviceInfo &device);
|
||||
void speedChanged(double);
|
||||
void inclinationChanged(double);
|
||||
|
||||
signals:
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ void bluetoothdevice::start(){ requestStart = 1; }
|
||||
void bluetoothdevice::stop(){ requestStop = 1; }
|
||||
unsigned char bluetoothdevice::currentHeart(){ return Heart; }
|
||||
double bluetoothdevice::currentSpeed(){ return Speed; }
|
||||
QTime bluetoothdevice::currentPace(){ return QTime(0, (int)(1.0 / (Speed / 60.0)), (((double)(1.0 / (Speed / 60.0)) - ((double)((int)(1.0 / (Speed / 60.0))))) * 60.0), 0 ); }
|
||||
QTime bluetoothdevice::currentPace(){ if(Speed == 0) return QTime(0,0,0,0); else return QTime(0, (int)(1.0 / (Speed / 60.0)), (((double)(1.0 / (Speed / 60.0)) - ((double)((int)(1.0 / (Speed / 60.0))))) * 60.0), 0 ); }
|
||||
double bluetoothdevice::odometer(){ return Distance; }
|
||||
double bluetoothdevice::calories(){ return KCal; }
|
||||
uint8_t bluetoothdevice::fanSpeed() { return FanSpeed; };
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
#define BLUETOOTHDEVICE_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QBluetoothDeviceInfo>
|
||||
|
||||
class bluetoothdevice : public QObject
|
||||
{
|
||||
@@ -18,6 +19,7 @@ public:
|
||||
virtual void* VirtualDevice();
|
||||
uint16_t watts(double weight=75.0);
|
||||
virtual bool changeFanSpeed(uint8_t speed);
|
||||
QBluetoothDeviceInfo bluetoothDevice;
|
||||
|
||||
enum BLUETOOTH_TYPE {
|
||||
UNKNOWN = 0,
|
||||
|
||||
@@ -129,7 +129,7 @@ void domyosbike::update()
|
||||
//else
|
||||
// btinit_telink(false);
|
||||
}
|
||||
else if(btbike.isValid() &&
|
||||
else if(bluetoothDevice.isValid() &&
|
||||
m_control->state() == QLowEnergyController::DiscoveredState &&
|
||||
gattCommunicationChannelService &&
|
||||
gattWriteCharacteristic.isValid() &&
|
||||
@@ -455,7 +455,7 @@ void domyosbike::deviceDiscovered(const QBluetoothDeviceInfo &device)
|
||||
debug("Found new device: " + device.name() + " (" + device.address().toString() + ')');
|
||||
if(device.name().startsWith("Domyos-Bike") && !device.name().startsWith("DomyosBridge"))
|
||||
{
|
||||
btbike = device;
|
||||
bluetoothDevice = device;
|
||||
|
||||
if(device.address().toString().startsWith("57"))
|
||||
{
|
||||
@@ -468,7 +468,7 @@ void domyosbike::deviceDiscovered(const QBluetoothDeviceInfo &device)
|
||||
bike_type = CHANG_YOW;
|
||||
}
|
||||
|
||||
m_control = QLowEnergyController::createCentral(btbike, this);
|
||||
m_control = QLowEnergyController::createCentral(bluetoothDevice, this);
|
||||
connect(m_control, SIGNAL(serviceDiscovered(const QBluetoothUuid &)),
|
||||
this, SLOT(serviceDiscovered(const QBluetoothUuid &)));
|
||||
connect(m_control, SIGNAL(discoveryFinished()),
|
||||
|
||||
@@ -53,7 +53,6 @@ private:
|
||||
QTimer* refresh;
|
||||
virtualbike* virtualBike = 0;
|
||||
|
||||
QBluetoothDeviceInfo btbike;
|
||||
QLowEnergyController* m_control = 0;
|
||||
QLowEnergyService* gattCommunicationChannelService = 0;
|
||||
QLowEnergyCharacteristic gattWriteCharacteristic;
|
||||
|
||||
@@ -5,6 +5,9 @@
|
||||
#include <QMetaEnum>
|
||||
#include <QBluetoothLocalDevice>
|
||||
|
||||
static double lastSpeed = 0.0;
|
||||
static double lastInclination = 0;
|
||||
|
||||
// set speed and incline to 0
|
||||
uint8_t initData1[] = { 0xf0, 0xc8, 0x01, 0xb9 };
|
||||
uint8_t initData2[] = { 0xf0, 0xc9, 0xb9 };
|
||||
@@ -49,7 +52,6 @@ QBluetoothUuid _gattCommunicationChannelServiceId((QString)"49535343-fe7d-4ae5-8
|
||||
QBluetoothUuid _gattWriteCharacteristicId((QString)"49535343-8841-43f4-a8d4-ecbe34729bb3");
|
||||
QBluetoothUuid _gattNotifyCharacteristicId((QString)"49535343-1e4d-4bd9-ba61-23c647249616");
|
||||
|
||||
QBluetoothDeviceInfo bttreadmill;
|
||||
QLowEnergyController* m_control = 0;
|
||||
QLowEnergyService* gattCommunicationChannelService = 0;
|
||||
QLowEnergyCharacteristic gattWriteCharacteristic;
|
||||
@@ -58,10 +60,17 @@ QLowEnergyCharacteristic gattNotifyCharacteristic;
|
||||
bool initDone = false;
|
||||
bool initRequest = false;
|
||||
|
||||
domyostreadmill::domyostreadmill(uint32_t pollDeviceTime, bool noConsole, bool noHeartService)
|
||||
domyostreadmill::domyostreadmill(uint32_t pollDeviceTime, bool noConsole, bool noHeartService, double forceInitSpeed, double forceInitInclination)
|
||||
{
|
||||
this->noConsole = noConsole;
|
||||
this->noHeartService = noHeartService;
|
||||
|
||||
if(forceInitSpeed > 0)
|
||||
lastSpeed = forceInitSpeed;
|
||||
|
||||
if(forceInitInclination > 0)
|
||||
lastInclination = forceInitInclination;
|
||||
|
||||
refresh = new QTimer(this);
|
||||
initDone = false;
|
||||
connect(refresh, SIGNAL(timeout()), this, SLOT(update()));
|
||||
@@ -136,8 +145,8 @@ void domyostreadmill::updateDisplay(uint16_t elapsed)
|
||||
display[26] += display[i]; // the last byte is a sort of a checksum
|
||||
}
|
||||
|
||||
writeCharacteristic(display, 20, "updateDisplay elapsed=" + QString::number(elapsed) );
|
||||
writeCharacteristic(&display[20], sizeof (display) - 20, "updateDisplay elapsed=" + QString::number(elapsed) );
|
||||
writeCharacteristic(display, 20, "updateDisplay elapsed=" + QString::number(elapsed), false, false );
|
||||
writeCharacteristic(&display[20], sizeof (display) - 20, "updateDisplay elapsed=" + QString::number(elapsed), false, true );
|
||||
}
|
||||
|
||||
void domyostreadmill::forceSpeedOrIncline(double requestSpeed, double requestIncline)
|
||||
@@ -161,8 +170,8 @@ void domyostreadmill::forceSpeedOrIncline(double requestSpeed, double requestInc
|
||||
//qDebug() << "writeIncline crc" << QString::number(writeIncline[26], 16);
|
||||
|
||||
|
||||
writeCharacteristic(writeIncline, 20, "forceSpeedOrIncline speed=" + QString::number(requestSpeed) + " incline=" + QString::number(requestIncline));
|
||||
writeCharacteristic(&writeIncline[20], sizeof (writeIncline) - 20, "forceSpeedOrIncline speed=" + QString::number(requestSpeed) + " incline=" + QString::number(requestIncline));
|
||||
writeCharacteristic(writeIncline, 20, "forceSpeedOrIncline speed=" + QString::number(requestSpeed) + " incline=" + QString::number(requestIncline), false, false);
|
||||
writeCharacteristic(&writeIncline[20], sizeof (writeIncline) - 20, "forceSpeedOrIncline speed=" + QString::number(requestSpeed) + " incline=" + QString::number(requestIncline), false, true);
|
||||
}
|
||||
|
||||
bool domyostreadmill::changeFanSpeed(uint8_t speed)
|
||||
@@ -178,7 +187,7 @@ bool domyostreadmill::changeFanSpeed(uint8_t speed)
|
||||
fanSpeed[3] += fanSpeed[i]; // the last byte is a sort of a checksum
|
||||
}
|
||||
|
||||
writeCharacteristic(fanSpeed, 4, "changeFanSpeed speed=" + QString::number(speed));
|
||||
writeCharacteristic(fanSpeed, 4, "changeFanSpeed speed=" + QString::number(speed), false, true);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -199,15 +208,36 @@ void domyostreadmill::update()
|
||||
if(initRequest)
|
||||
{
|
||||
initRequest = false;
|
||||
btinit(false);
|
||||
btinit((lastSpeed > 0 ? true : false));
|
||||
}
|
||||
else if(bttreadmill.isValid() &&
|
||||
else if(bluetoothDevice.isValid() &&
|
||||
m_control->state() == QLowEnergyController::DiscoveredState &&
|
||||
gattCommunicationChannelService &&
|
||||
gattWriteCharacteristic.isValid() &&
|
||||
gattNotifyCharacteristic.isValid() &&
|
||||
initDone)
|
||||
{
|
||||
// ******************************************* virtual treadmill init *************************************
|
||||
static uint8_t firstInit = 0;
|
||||
if(!firstInit)
|
||||
{
|
||||
debug("creating virtual treadmill interface...");
|
||||
virtualTreadMill = new virtualtreadmill(this, noHeartService);
|
||||
|
||||
#ifdef Q_OS_LINUX
|
||||
#ifndef Q_OS_ANDROID
|
||||
// on raspberry, the very first time you run the bridge it doesn't work. let's try in this way
|
||||
delete virtualTreadMill;
|
||||
virtualTreadMill = new virtualtreadmill(this, noHeartService);
|
||||
#endif
|
||||
#endif
|
||||
connect(virtualTreadMill,&virtualtreadmill::debug ,this,&domyostreadmill::debug);
|
||||
}
|
||||
firstInit = 1;
|
||||
// ********************************************************************************************************
|
||||
|
||||
debug("Domyos Treadmill RSSI " + QString::number(bluetoothDevice.rssi()));
|
||||
|
||||
QDateTime current = QDateTime::currentDateTime();
|
||||
if(currentSpeed() > 0.0 && !first)
|
||||
elapsed += (((double)lastTime.msecsTo(current)) / ((double)1000.0));
|
||||
@@ -263,6 +293,8 @@ void domyostreadmill::update()
|
||||
if(requestStart != -1)
|
||||
{
|
||||
debug("starting...");
|
||||
if(lastSpeed == 0.0)
|
||||
lastSpeed = 0.5;
|
||||
btinit(true);
|
||||
requestStart = -1;
|
||||
emit tapeStarted();
|
||||
@@ -287,7 +319,7 @@ void domyostreadmill::update()
|
||||
}
|
||||
}
|
||||
|
||||
elevationAcc += (currentSpeed() / 3600.0) * 1000 * (currentInclination() / 100) * (refresh->interval() / 1000);
|
||||
elevationAcc += (currentSpeed() / 3600.0) * 1000.0 * (currentInclination() / 100.0) * ((double)refresh->interval() / 1000.0);
|
||||
}
|
||||
|
||||
first = false;
|
||||
@@ -390,11 +422,26 @@ void domyostreadmill::characteristicChanged(const QLowEnergyCharacteristic &char
|
||||
if(m_control->error() != QLowEnergyController::NoError)
|
||||
qDebug() << "QLowEnergyController ERROR!!" << m_control->errorString();
|
||||
|
||||
Speed = speed;
|
||||
Inclination = incline;
|
||||
if(Speed != speed)
|
||||
{
|
||||
Speed = speed;
|
||||
emit speedChanged(speed);
|
||||
}
|
||||
if(Inclination != incline)
|
||||
{
|
||||
Inclination = incline;
|
||||
emit inclinationChanged(incline);
|
||||
}
|
||||
|
||||
KCal = kcal;
|
||||
Distance = distance;
|
||||
|
||||
if(speed > 0)
|
||||
{
|
||||
lastSpeed = speed;
|
||||
lastInclination = incline;
|
||||
}
|
||||
|
||||
lastTime = QDateTime::currentDateTime();
|
||||
first = false;
|
||||
}
|
||||
@@ -422,7 +469,12 @@ double domyostreadmill::GetDistanceFromPacket(QByteArray packet)
|
||||
double domyostreadmill::GetInclinationFromPacket(QByteArray packet)
|
||||
{
|
||||
uint16_t convertedData = (packet.at(2) << 8) | packet.at(3);
|
||||
double data = ((double)convertedData - 1000.0f) / 10.0f;
|
||||
double data;
|
||||
|
||||
if(convertedData > 10000)
|
||||
data = ((double)convertedData - 65512.0f) / 10.0f;
|
||||
else
|
||||
data = ((double)convertedData - 1000.0f) / 10.0f;
|
||||
if (data < 0) return 0;
|
||||
return data;
|
||||
}
|
||||
@@ -436,16 +488,20 @@ void domyostreadmill::btinit(bool startTape)
|
||||
writeCharacteristic(initDataStart3, sizeof(initDataStart3), "init", false, true);
|
||||
writeCharacteristic(initDataStart4, sizeof(initDataStart4), "init", false, true);
|
||||
writeCharacteristic(initDataStart5, sizeof(initDataStart5), "init", false, true);
|
||||
writeCharacteristic(initDataStart6, sizeof(initDataStart6), "init", false, false);
|
||||
writeCharacteristic(initDataStart7, sizeof(initDataStart7), "init", false, true);
|
||||
//writeCharacteristic(initDataStart6, sizeof(initDataStart6), "init", false, false);
|
||||
//writeCharacteristic(initDataStart7, sizeof(initDataStart7), "init", false, true);
|
||||
forceSpeedOrIncline(lastSpeed, lastInclination);
|
||||
|
||||
writeCharacteristic(initDataStart8, sizeof(initDataStart8), "init", false, false);
|
||||
writeCharacteristic(initDataStart9, sizeof(initDataStart9), "init", false, true);
|
||||
writeCharacteristic(initDataStart10, sizeof(initDataStart10), "init", false, false);
|
||||
writeCharacteristic(initDataStart9, sizeof(initDataStart9), "init", false, true);
|
||||
if(startTape)
|
||||
{
|
||||
writeCharacteristic(initDataStart10, sizeof(initDataStart10), "init", false, false);
|
||||
writeCharacteristic(initDataStart11, sizeof(initDataStart11), "init", false, true);
|
||||
writeCharacteristic(initDataStart12, sizeof(initDataStart12), "init", false, false);
|
||||
writeCharacteristic(initDataStart13, sizeof(initDataStart13), "init", false, true);
|
||||
|
||||
forceSpeedOrIncline(lastSpeed, lastInclination);
|
||||
}
|
||||
|
||||
initDone = true;
|
||||
@@ -474,17 +530,6 @@ void domyostreadmill::stateChanged(QLowEnergyService::ServiceState state)
|
||||
connect(gattCommunicationChannelService, SIGNAL(descriptorWritten(const QLowEnergyDescriptor, const QByteArray)), this,
|
||||
SLOT(descriptorWritten(const QLowEnergyDescriptor, const QByteArray)));
|
||||
|
||||
// ******************************************* virtual treadmill init *************************************
|
||||
static uint8_t first = 0;
|
||||
if(!first)
|
||||
{
|
||||
debug("creating virtual treadmill interface...");
|
||||
virtualTreadMill = new virtualtreadmill(this, noHeartService);
|
||||
connect(virtualTreadMill,&virtualtreadmill::debug ,this,&domyostreadmill::debug);
|
||||
}
|
||||
first = 1;
|
||||
// ********************************************************************************************************
|
||||
|
||||
QByteArray descriptor;
|
||||
descriptor.append((char)0x01);
|
||||
descriptor.append((char)0x00);
|
||||
@@ -532,8 +577,8 @@ void domyostreadmill::deviceDiscovered(const QBluetoothDeviceInfo &device)
|
||||
debug("Found new device: " + device.name() + " (" + device.address().toString() + ')');
|
||||
if(device.name().startsWith("Domyos") && !device.name().startsWith("DomyosBridge"))
|
||||
{
|
||||
bttreadmill = device;
|
||||
m_control = QLowEnergyController::createCentral(bttreadmill, this);
|
||||
bluetoothDevice = device;
|
||||
m_control = QLowEnergyController::createCentral(bluetoothDevice, this);
|
||||
connect(m_control, SIGNAL(serviceDiscovered(const QBluetoothUuid &)),
|
||||
this, SLOT(serviceDiscovered(const QBluetoothUuid &)));
|
||||
connect(m_control, SIGNAL(discoveryFinished()),
|
||||
@@ -586,3 +631,13 @@ double domyostreadmill::odometer()
|
||||
{
|
||||
return DistanceCalculated;
|
||||
}
|
||||
|
||||
void domyostreadmill::setLastSpeed(double speed)
|
||||
{
|
||||
lastSpeed = speed;
|
||||
}
|
||||
|
||||
void domyostreadmill::setLastInclination(double inclination)
|
||||
{
|
||||
lastInclination = inclination;
|
||||
}
|
||||
|
||||
@@ -31,11 +31,14 @@ class domyostreadmill : public treadmill
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
domyostreadmill(uint32_t poolDeviceTime = 200, bool noConsole = false, bool noHeartService = false);
|
||||
domyostreadmill(uint32_t poolDeviceTime = 200, bool noConsole = false, bool noHeartService = false, double forceInitSpeed = 0.0, double forceInitInclination = 0.0);
|
||||
bool connected();
|
||||
bool changeFanSpeed(uint8_t speed);
|
||||
double odometer();
|
||||
|
||||
void setLastSpeed(double speed);
|
||||
void setLastInclination(double inclination);
|
||||
|
||||
void* VirtualTreadMill();
|
||||
void* VirtualDevice();
|
||||
|
||||
@@ -61,6 +64,8 @@ private:
|
||||
signals:
|
||||
void disconnected();
|
||||
void debug(QString string);
|
||||
void speedChanged(double speed);
|
||||
void inclinationChanged(double inclination);
|
||||
|
||||
public slots:
|
||||
void deviceDiscovered(const QBluetoothDeviceInfo &device);
|
||||
|
||||
361
src/echelonconnectsport.cpp
Normal file
361
src/echelonconnectsport.cpp
Normal file
@@ -0,0 +1,361 @@
|
||||
#include "echelonconnectsport.h"
|
||||
#include "virtualbike.h"
|
||||
#include <QFile>
|
||||
#include <QDateTime>
|
||||
#include <QMetaEnum>
|
||||
#include <QBluetoothLocalDevice>
|
||||
|
||||
echelonconnectsport::echelonconnectsport(bool noWriteResistance, bool noHeartService)
|
||||
{
|
||||
refresh = new QTimer(this);
|
||||
this->noWriteResistance = noWriteResistance;
|
||||
this->noHeartService = noHeartService;
|
||||
initDone = false;
|
||||
connect(refresh, SIGNAL(timeout()), this, SLOT(update()));
|
||||
refresh->start(200);
|
||||
}
|
||||
|
||||
void echelonconnectsport::writeCharacteristic(uint8_t* data, uint8_t data_len, QString info, bool disable_log, bool wait_for_response)
|
||||
{
|
||||
QEventLoop loop;
|
||||
if(wait_for_response)
|
||||
{
|
||||
connect(gattCommunicationChannelService, SIGNAL(characteristicChanged(QLowEnergyCharacteristic,QByteArray)),
|
||||
&loop, SLOT(quit()));
|
||||
}
|
||||
else
|
||||
{
|
||||
connect(gattCommunicationChannelService, SIGNAL(characteristicWritten(QLowEnergyCharacteristic,QByteArray)),
|
||||
&loop, SLOT(quit()));
|
||||
}
|
||||
|
||||
gattCommunicationChannelService->writeCharacteristic(gattWriteCharacteristic, QByteArray::fromRawData((const char*)data, data_len));
|
||||
|
||||
if(!disable_log)
|
||||
debug(" >> " + QByteArray((const char*)data, data_len).toHex(' ') + " // " + info);
|
||||
|
||||
loop.exec();
|
||||
}
|
||||
|
||||
void echelonconnectsport::sendPoll()
|
||||
{
|
||||
static uint8_t counter = 1;
|
||||
uint8_t noOpData[] = { 0xf0, 0xa0, 0x01, 0x00, 0x00 };
|
||||
|
||||
noOpData[3] = counter;
|
||||
|
||||
for(uint8_t i=0; i<sizeof(noOpData)-1; i++)
|
||||
{
|
||||
noOpData[4] += noOpData[i]; // the last byte is a sort of a checksum
|
||||
}
|
||||
|
||||
writeCharacteristic(noOpData, sizeof(noOpData), "noOp", true);
|
||||
|
||||
counter++;
|
||||
if(!counter)
|
||||
counter = 1;
|
||||
}
|
||||
|
||||
void echelonconnectsport::update()
|
||||
{
|
||||
static QDateTime lastTime;
|
||||
static bool first = true;
|
||||
|
||||
static uint8_t sec1 = 0;
|
||||
|
||||
if(m_control->state() == QLowEnergyController::UnconnectedState)
|
||||
{
|
||||
emit disconnected();
|
||||
return;
|
||||
}
|
||||
|
||||
if(initRequest)
|
||||
{
|
||||
initRequest = false;
|
||||
btinit();
|
||||
}
|
||||
else if(bluetoothDevice.isValid() &&
|
||||
m_control->state() == QLowEnergyController::DiscoveredState &&
|
||||
gattCommunicationChannelService &&
|
||||
gattWriteCharacteristic.isValid() &&
|
||||
gattNotify1Characteristic.isValid() &&
|
||||
gattNotify2Characteristic.isValid() &&
|
||||
initDone)
|
||||
{
|
||||
QDateTime current = QDateTime::currentDateTime();
|
||||
if(currentSpeed() > 0.0 && !first)
|
||||
elapsed += (((double)lastTime.msecsTo(current)) / ((double)1000.0));
|
||||
lastTime = current;
|
||||
|
||||
// updating the treadmill console every second
|
||||
if(sec1++ == (500 / refresh->interval()))
|
||||
{
|
||||
sec1 = 0;
|
||||
//updateDisplay(elapsed);
|
||||
}
|
||||
|
||||
sendPoll();
|
||||
|
||||
if(requestResistance != -1)
|
||||
{
|
||||
if(requestResistance > 15) requestResistance = 15;
|
||||
else if(requestResistance == 0) requestResistance = 1;
|
||||
|
||||
if(requestResistance != currentResistance())
|
||||
{
|
||||
debug("writing resistance " + QString::number(requestResistance));
|
||||
//forceResistance(requestResistance);
|
||||
}
|
||||
requestResistance = -1;
|
||||
}
|
||||
if(requestStart != -1)
|
||||
{
|
||||
debug("starting...");
|
||||
|
||||
btinit();
|
||||
|
||||
requestStart = -1;
|
||||
emit bikeStarted();
|
||||
}
|
||||
if(requestStop != -1)
|
||||
{
|
||||
debug("stopping...");
|
||||
//writeCharacteristic(initDataF0C800B8, sizeof(initDataF0C800B8), "stop tape");
|
||||
requestStop = -1;
|
||||
}
|
||||
}
|
||||
|
||||
first = false;
|
||||
}
|
||||
|
||||
void echelonconnectsport::serviceDiscovered(const QBluetoothUuid &gatt)
|
||||
{
|
||||
debug("serviceDiscovered " + gatt.toString());
|
||||
}
|
||||
|
||||
static QByteArray lastPacket;
|
||||
void echelonconnectsport::characteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &newValue)
|
||||
{
|
||||
//qDebug() << "characteristicChanged" << characteristic.uuid() << newValue << newValue.length();
|
||||
Q_UNUSED(characteristic);
|
||||
static QDateTime lastRefresh = QDateTime::currentDateTime();
|
||||
|
||||
debug(" << " + newValue.toHex(' '));
|
||||
|
||||
if (lastPacket.length() && lastPacket == newValue)
|
||||
return;
|
||||
|
||||
lastPacket = newValue;
|
||||
|
||||
// resistance value is in another frame
|
||||
if(newValue.length() == 5 && (uint8_t)(newValue.at(0)) != 0xf0 && (uint8_t)(newValue.at(1)) != 0xd2)
|
||||
{
|
||||
Resistance = newValue.at(3);
|
||||
debug("Current resistance: " + QString::number(Resistance));
|
||||
return;
|
||||
}
|
||||
|
||||
if (newValue.length() != 13)
|
||||
return;
|
||||
|
||||
/*if ((uint8_t)(newValue.at(0)) != 0xf0 && (uint8_t)(newValue.at(1)) != 0xd1)
|
||||
return;*/
|
||||
|
||||
double distance = GetDistanceFromPacket(newValue);
|
||||
|
||||
Cadence = newValue.at(10);
|
||||
|
||||
CrankRevs += ((double)(lastRefresh.msecsTo(QDateTime::currentDateTime())) * ((double)Cadence / 60000.0) );
|
||||
LastCrankEventTime += (uint16_t)((lastRefresh.msecsTo(QDateTime::currentDateTime())) * 1.024);
|
||||
lastRefresh = QDateTime::currentDateTime();
|
||||
|
||||
debug("Current Local elapsed: " + GetElapsedFromPacket(newValue).toString());
|
||||
debug("Current cadence: " + QString::number(Cadence));
|
||||
debug("Current Distance: " + QString::number(distance));
|
||||
debug("Current CrankRevs: " + QString::number(CrankRevs));
|
||||
debug("Last CrankEventTime: " + QString::number(LastCrankEventTime));
|
||||
debug("Current Watt: " + QString::number(watts()));
|
||||
|
||||
if(m_control->error() != QLowEnergyController::NoError)
|
||||
qDebug() << "QLowEnergyController ERROR!!" << m_control->errorString();
|
||||
|
||||
Speed = 0;
|
||||
KCal = 0;
|
||||
Distance = distance;
|
||||
}
|
||||
|
||||
QTime echelonconnectsport::GetElapsedFromPacket(QByteArray packet)
|
||||
{
|
||||
uint16_t convertedData = (packet.at(3) << 8) | packet.at(4);
|
||||
QTime t(0,convertedData / 60, convertedData % 60);
|
||||
return t;
|
||||
}
|
||||
|
||||
double echelonconnectsport::GetDistanceFromPacket(QByteArray packet)
|
||||
{
|
||||
uint16_t convertedData = (packet.at(7) << 8) | packet.at(8);
|
||||
double data = ((double)convertedData) / 10.0f;
|
||||
return data;
|
||||
}
|
||||
|
||||
void echelonconnectsport::btinit()
|
||||
{
|
||||
uint8_t initData1[] = { 0xf0, 0xa1, 0x00, 0x91 };
|
||||
uint8_t initData2[] = { 0xf0, 0xa3, 0x00, 0x93 };
|
||||
uint8_t initData3[] = { 0xf0, 0xb0, 0x01, 0x01, 0xa2 };
|
||||
|
||||
// in the snoof log it repeats this frame 4 times, i will have to analyze the response to understand if 4 times are enough
|
||||
writeCharacteristic(initData1, sizeof(initData1), "init", false, true);
|
||||
writeCharacteristic(initData1, sizeof(initData1), "init", false, true);
|
||||
writeCharacteristic(initData1, sizeof(initData1), "init", false, true);
|
||||
writeCharacteristic(initData1, sizeof(initData1), "init", false, true);
|
||||
|
||||
writeCharacteristic(initData2, sizeof(initData2), "init", false, true);
|
||||
writeCharacteristic(initData1, sizeof(initData1), "init", false, true);
|
||||
writeCharacteristic(initData1, sizeof(initData3), "init", false, true);
|
||||
|
||||
initDone = true;
|
||||
}
|
||||
|
||||
void echelonconnectsport::stateChanged(QLowEnergyService::ServiceState state)
|
||||
{
|
||||
QBluetoothUuid _gattWriteCharacteristicId((QString)"0bf669f2-45f2-11e7-9598-0800200c9a66");
|
||||
QBluetoothUuid _gattNotify1CharacteristicId((QString)"0bf669f3-45f2-11e7-9598-0800200c9a66");
|
||||
QBluetoothUuid _gattNotify2CharacteristicId((QString)"0bf669f4-45f2-11e7-9598-0800200c9a66");
|
||||
|
||||
QMetaEnum metaEnum = QMetaEnum::fromType<QLowEnergyService::ServiceState>();
|
||||
debug("BTLE stateChanged " + QString::fromLocal8Bit(metaEnum.valueToKey(state)));
|
||||
|
||||
if(state == QLowEnergyService::ServiceDiscovered)
|
||||
{
|
||||
//qDebug() << gattCommunicationChannelService->characteristics();
|
||||
|
||||
gattWriteCharacteristic = gattCommunicationChannelService->characteristic(_gattWriteCharacteristicId);
|
||||
gattNotify1Characteristic = gattCommunicationChannelService->characteristic(_gattNotify1CharacteristicId);
|
||||
gattNotify2Characteristic = gattCommunicationChannelService->characteristic(_gattNotify2CharacteristicId);
|
||||
Q_ASSERT(gattWriteCharacteristic.isValid());
|
||||
Q_ASSERT(gattNotify1Characteristic.isValid());
|
||||
Q_ASSERT(gattNotify2Characteristic.isValid());
|
||||
|
||||
// establish hook into notifications
|
||||
connect(gattCommunicationChannelService, SIGNAL(characteristicChanged(QLowEnergyCharacteristic,QByteArray)),
|
||||
this, SLOT(characteristicChanged(QLowEnergyCharacteristic,QByteArray)));
|
||||
connect(gattCommunicationChannelService, SIGNAL(characteristicWritten(const QLowEnergyCharacteristic, const QByteArray)),
|
||||
this, SLOT(characteristicWritten(const QLowEnergyCharacteristic, const QByteArray)));
|
||||
connect(gattCommunicationChannelService, SIGNAL(error(QLowEnergyService::ServiceError)),
|
||||
this, SLOT(errorService(QLowEnergyService::ServiceError)));
|
||||
connect(gattCommunicationChannelService, SIGNAL(descriptorWritten(const QLowEnergyDescriptor, const QByteArray)), this,
|
||||
SLOT(descriptorWritten(const QLowEnergyDescriptor, const QByteArray)));
|
||||
|
||||
// ******************************************* virtual bike init *************************************
|
||||
static uint8_t first = 0;
|
||||
if(!first)
|
||||
{
|
||||
debug("creating virtual bike interface...");
|
||||
virtualBike = new virtualbike(this, noWriteResistance, noHeartService);
|
||||
connect(virtualBike,&virtualbike::debug ,this,&echelonconnectsport::debug);
|
||||
}
|
||||
first = 1;
|
||||
// ********************************************************************************************************
|
||||
|
||||
QByteArray descriptor;
|
||||
descriptor.append((char)0x01);
|
||||
descriptor.append((char)0x00);
|
||||
gattCommunicationChannelService->writeDescriptor(gattNotify1Characteristic.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration), descriptor);
|
||||
gattCommunicationChannelService->writeDescriptor(gattNotify2Characteristic.descriptor(QBluetoothUuid::ClientCharacteristicConfiguration), descriptor);
|
||||
}
|
||||
}
|
||||
|
||||
void echelonconnectsport::descriptorWritten(const QLowEnergyDescriptor &descriptor, const QByteArray &newValue)
|
||||
{
|
||||
debug("descriptorWritten " + descriptor.name() + " " + newValue.toHex(' '));
|
||||
|
||||
initRequest = true;
|
||||
}
|
||||
|
||||
void echelonconnectsport::characteristicWritten(const QLowEnergyCharacteristic &characteristic, const QByteArray &newValue)
|
||||
{
|
||||
Q_UNUSED(characteristic);
|
||||
debug("characteristicWritten " + newValue.toHex(' '));
|
||||
}
|
||||
|
||||
void echelonconnectsport::serviceScanDone(void)
|
||||
{
|
||||
debug("serviceScanDone");
|
||||
|
||||
QBluetoothUuid _gattCommunicationChannelServiceId((QString)"0bf669f1-45f2-11e7-9598-0800200c9a66");
|
||||
|
||||
gattCommunicationChannelService = m_control->createServiceObject(_gattCommunicationChannelServiceId);
|
||||
connect(gattCommunicationChannelService, SIGNAL(stateChanged(QLowEnergyService::ServiceState)), this, SLOT(stateChanged(QLowEnergyService::ServiceState)));
|
||||
gattCommunicationChannelService->discoverDetails();
|
||||
}
|
||||
|
||||
void echelonconnectsport::errorService(QLowEnergyService::ServiceError err)
|
||||
{
|
||||
QMetaEnum metaEnum = QMetaEnum::fromType<QLowEnergyService::ServiceError>();
|
||||
debug("echelonconnectsport::errorService" + QString::fromLocal8Bit(metaEnum.valueToKey(err)) + m_control->errorString());
|
||||
}
|
||||
|
||||
void echelonconnectsport::error(QLowEnergyController::Error err)
|
||||
{
|
||||
QMetaEnum metaEnum = QMetaEnum::fromType<QLowEnergyController::Error>();
|
||||
debug("echelonconnectsport::error" + QString::fromLocal8Bit(metaEnum.valueToKey(err)) + m_control->errorString());
|
||||
|
||||
m_control->disconnect();
|
||||
}
|
||||
|
||||
void echelonconnectsport::deviceDiscovered(const QBluetoothDeviceInfo &device)
|
||||
{
|
||||
debug("Found new device: " + device.name() + " (" + device.address().toString() + ')');
|
||||
if(device.name().startsWith("ECH-SPORT"))
|
||||
{
|
||||
bluetoothDevice = device;
|
||||
|
||||
m_control = QLowEnergyController::createCentral(bluetoothDevice, this);
|
||||
connect(m_control, SIGNAL(serviceDiscovered(const QBluetoothUuid &)),
|
||||
this, SLOT(serviceDiscovered(const QBluetoothUuid &)));
|
||||
connect(m_control, SIGNAL(discoveryFinished()),
|
||||
this, SLOT(serviceScanDone()));
|
||||
connect(m_control, SIGNAL(error(QLowEnergyController::Error)),
|
||||
this, SLOT(error(QLowEnergyController::Error)));
|
||||
|
||||
connect(m_control, static_cast<void (QLowEnergyController::*)(QLowEnergyController::Error)>(&QLowEnergyController::error),
|
||||
this, [this](QLowEnergyController::Error error) {
|
||||
Q_UNUSED(error);
|
||||
Q_UNUSED(this);
|
||||
debug("Cannot connect to remote device.");
|
||||
emit disconnected();
|
||||
});
|
||||
connect(m_control, &QLowEnergyController::connected, this, [this]() {
|
||||
Q_UNUSED(this);
|
||||
debug("Controller connected. Search services...");
|
||||
m_control->discoverServices();
|
||||
});
|
||||
connect(m_control, &QLowEnergyController::disconnected, this, [this]() {
|
||||
Q_UNUSED(this);
|
||||
debug("LowEnergy controller disconnected");
|
||||
emit disconnected();
|
||||
});
|
||||
|
||||
// Connect
|
||||
m_control->connectToDevice();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bool echelonconnectsport::connected()
|
||||
{
|
||||
if(!m_control)
|
||||
return false;
|
||||
return m_control->state() == QLowEnergyController::DiscoveredState;
|
||||
}
|
||||
|
||||
void* echelonconnectsport::VirtualBike()
|
||||
{
|
||||
return virtualBike;
|
||||
}
|
||||
|
||||
void* echelonconnectsport::VirtualDevice()
|
||||
{
|
||||
return VirtualBike();
|
||||
}
|
||||
86
src/echelonconnectsport.h
Normal file
86
src/echelonconnectsport.h
Normal file
@@ -0,0 +1,86 @@
|
||||
#ifndef ECHELONCONNECTSPORT_H
|
||||
#define ECHELONCONNECTSPORT_H
|
||||
|
||||
|
||||
#include <QtBluetooth/qlowenergyadvertisingdata.h>
|
||||
#include <QtBluetooth/qlowenergyadvertisingparameters.h>
|
||||
#include <QtBluetooth/qlowenergycharacteristic.h>
|
||||
#include <QtBluetooth/qlowenergycharacteristicdata.h>
|
||||
#include <QtBluetooth/qlowenergydescriptordata.h>
|
||||
#include <QtBluetooth/qlowenergycontroller.h>
|
||||
#include <QtBluetooth/qlowenergyservice.h>
|
||||
#include <QtBluetooth/qlowenergyservicedata.h>
|
||||
#include <QBluetoothDeviceDiscoveryAgent>
|
||||
#include <QtCore/qbytearray.h>
|
||||
|
||||
#ifndef Q_OS_ANDROID
|
||||
#include <QtCore/qcoreapplication.h>
|
||||
#else
|
||||
#include <QtGui/qguiapplication.h>
|
||||
#endif
|
||||
#include <QtCore/qlist.h>
|
||||
#include <QtCore/qscopedpointer.h>
|
||||
#include <QtCore/qtimer.h>
|
||||
#include <QtCore/qmutex.h>
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
|
||||
#include "virtualbike.h"
|
||||
#include "bike.h"
|
||||
|
||||
class echelonconnectsport : public bike
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
echelonconnectsport(bool noWriteResistance, bool noHeartService);
|
||||
bool connected();
|
||||
|
||||
void* VirtualBike();
|
||||
void* VirtualDevice();
|
||||
|
||||
private:
|
||||
double GetDistanceFromPacket(QByteArray packet);
|
||||
QTime GetElapsedFromPacket(QByteArray packet);
|
||||
void btinit();
|
||||
void writeCharacteristic(uint8_t* data, uint8_t data_len, QString info, bool disable_log=false, bool wait_for_response = false);
|
||||
void startDiscover();
|
||||
void sendPoll();
|
||||
|
||||
QTimer* refresh;
|
||||
virtualbike* virtualBike = 0;
|
||||
|
||||
QLowEnergyController* m_control = 0;
|
||||
QLowEnergyService* gattCommunicationChannelService = 0;
|
||||
QLowEnergyCharacteristic gattWriteCharacteristic;
|
||||
QLowEnergyCharacteristic gattNotify1Characteristic;
|
||||
QLowEnergyCharacteristic gattNotify2Characteristic;
|
||||
|
||||
bool initDone = false;
|
||||
bool initRequest = false;
|
||||
|
||||
bool noWriteResistance = false;
|
||||
bool noHeartService = false;
|
||||
|
||||
signals:
|
||||
void disconnected();
|
||||
void debug(QString string);
|
||||
|
||||
public slots:
|
||||
void deviceDiscovered(const QBluetoothDeviceInfo &device);
|
||||
|
||||
private slots:
|
||||
|
||||
void characteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &newValue);
|
||||
void characteristicWritten(const QLowEnergyCharacteristic &characteristic, const QByteArray &newValue);
|
||||
void descriptorWritten(const QLowEnergyDescriptor &descriptor, const QByteArray &newValue);
|
||||
void stateChanged(QLowEnergyService::ServiceState state);
|
||||
|
||||
void serviceDiscovered(const QBluetoothUuid &gatt);
|
||||
void serviceScanDone(void);
|
||||
void update();
|
||||
void error(QLowEnergyController::Error err);
|
||||
void errorService(QLowEnergyService::ServiceError);
|
||||
};
|
||||
|
||||
#endif // ECHELONCONNECTSPORT_H
|
||||
@@ -15,26 +15,53 @@ DataObject::DataObject(QString name, QString icon, QString value, bool writable,
|
||||
}
|
||||
|
||||
void DataObject::setValue(QString v) {m_value = v; emit valueChanged(m_value);}
|
||||
void DataObject::setVisible(bool visible) {m_visible = visible; emit visibleChanged(m_visible);}
|
||||
|
||||
homeform::homeform(QQmlApplicationEngine* engine, bluetooth* bl)
|
||||
{
|
||||
this->bluetoothManager = bl;
|
||||
this->engine = engine;
|
||||
connect(bluetoothManager, SIGNAL(deviceFound(QString)), this, SLOT(deviceFound(QString)));
|
||||
connect(bluetoothManager, SIGNAL(deviceConnected()), this, SLOT(deviceConnected()));
|
||||
engine->rootContext()->setContextProperty("rootItem", (QObject *)this);
|
||||
|
||||
dataList = {
|
||||
speed,
|
||||
inclination,
|
||||
cadence,
|
||||
elevation,
|
||||
calories,
|
||||
odometer,
|
||||
pace,
|
||||
resistance,
|
||||
watt,
|
||||
heart,
|
||||
fan
|
||||
};
|
||||
timer = new QTimer(this);
|
||||
connect(timer, &QTimer::timeout, this, &homeform::update);
|
||||
timer->start(1000);
|
||||
}
|
||||
|
||||
void homeform::deviceConnected()
|
||||
{
|
||||
if(bluetoothManager->device()->deviceType() == bluetoothdevice::TREADMILL)
|
||||
{
|
||||
dataList = {
|
||||
speed,
|
||||
inclination,
|
||||
elevation,
|
||||
calories,
|
||||
odometer,
|
||||
pace,
|
||||
watt,
|
||||
heart,
|
||||
fan
|
||||
};
|
||||
|
||||
}
|
||||
else if(bluetoothManager->device()->deviceType() == bluetoothdevice::BIKE)
|
||||
{
|
||||
dataList = {
|
||||
speed,
|
||||
cadence,
|
||||
elevation,
|
||||
calories,
|
||||
odometer,
|
||||
resistance,
|
||||
watt,
|
||||
heart,
|
||||
fan
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
engine->rootContext()->setContextProperty("appModel", QVariant::fromValue(dataList));
|
||||
|
||||
@@ -48,14 +75,11 @@ homeform::homeform(QQmlApplicationEngine* engine, bluetooth* bl)
|
||||
this, SLOT(Plus(QString)));
|
||||
QObject::connect(home, SIGNAL(minus_clicked(QString)),
|
||||
this, SLOT(Minus(QString)));
|
||||
|
||||
timer = new QTimer(this);
|
||||
connect(timer, &QTimer::timeout, this, &homeform::update);
|
||||
timer->start(1000);
|
||||
}
|
||||
|
||||
void homeform::deviceFound(QString name)
|
||||
{
|
||||
if(!name.trimmed().length()) return;
|
||||
m_info = name + " founded";
|
||||
emit infoChanged(m_info);
|
||||
}
|
||||
@@ -159,6 +183,23 @@ void homeform::Stop()
|
||||
bluetoothManager->device()->stop();
|
||||
}
|
||||
|
||||
QString homeform::signal()
|
||||
{
|
||||
if(!bluetoothManager)
|
||||
return "icons/icons/signal-1.png";
|
||||
|
||||
if(!bluetoothManager->device())
|
||||
return "icons/icons/signal-1.png";
|
||||
|
||||
int16_t rssi = bluetoothManager->device()->bluetoothDevice.rssi();
|
||||
if(rssi > -40)
|
||||
return "icons/icons/signal-3.png";
|
||||
else if(rssi > -60)
|
||||
return "icons/icons/signal-2.png";
|
||||
|
||||
return "icons/icons/signal-1.png";
|
||||
}
|
||||
|
||||
void homeform::update()
|
||||
{
|
||||
if(bluetoothManager->device())
|
||||
@@ -168,6 +209,8 @@ void homeform::update()
|
||||
double watts = 0;
|
||||
double pace = 0;
|
||||
|
||||
emit signalChanged(signal());
|
||||
|
||||
speed->setValue(QString::number(bluetoothManager->device()->currentSpeed(), 'f', 2));
|
||||
heart->setValue(QString::number(bluetoothManager->device()->currentHeart()));
|
||||
odometer->setValue(QString::number(bluetoothManager->device()->odometer(), 'f', 2));
|
||||
@@ -176,8 +219,15 @@ void homeform::update()
|
||||
|
||||
if(bluetoothManager->device()->deviceType() == bluetoothdevice::TREADMILL)
|
||||
{
|
||||
pace = 10000 / (((treadmill*)bluetoothManager->device())->currentPace().second() + (((treadmill*)bluetoothManager->device())->currentPace().minute() * 60));
|
||||
if(pace < 0) pace = 0;
|
||||
if(bluetoothManager->device()->currentSpeed())
|
||||
{
|
||||
pace = 10000 / (((treadmill*)bluetoothManager->device())->currentPace().second() + (((treadmill*)bluetoothManager->device())->currentPace().minute() * 60));
|
||||
if(pace < 0) pace = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
pace = 0;
|
||||
}
|
||||
watts = ((treadmill*)bluetoothManager->device())->watts(/*weight->text().toFloat()*/); // TODO: add weight to settings
|
||||
inclination = ((treadmill*)bluetoothManager->device())->currentInclination();
|
||||
this->pace->setValue(((treadmill*)bluetoothManager->device())->currentPace().toString("m:ss"));
|
||||
@@ -191,6 +241,7 @@ void homeform::update()
|
||||
watts = ((bike*)bluetoothManager->device())->watts();
|
||||
watt->setValue(QString::number(watts));
|
||||
this->resistance->setValue(QString::number(resistance));
|
||||
this->cadence->setValue(QString::number(((bike*)bluetoothManager->device())->currentCadence()));
|
||||
}
|
||||
/*
|
||||
if(trainProgram)
|
||||
|
||||
@@ -14,16 +14,19 @@ class DataObject : public QObject
|
||||
Q_PROPERTY(QString icon READ icon NOTIFY iconChanged)
|
||||
Q_PROPERTY(QString value READ value WRITE setValue NOTIFY valueChanged)
|
||||
Q_PROPERTY(bool writable READ writable NOTIFY writableChanged)
|
||||
Q_PROPERTY(bool visibleItem READ visibleItem NOTIFY visibleChanged)
|
||||
Q_PROPERTY(QString plusName READ plusName NOTIFY plusNameChanged)
|
||||
Q_PROPERTY(QString minusName READ minusName NOTIFY minusNameChanged)
|
||||
|
||||
public:
|
||||
DataObject(QString name, QString icon, QString value, bool writable, QString id);
|
||||
void setValue(QString value);
|
||||
void setVisible(bool visible);
|
||||
QString name() {return m_name;}
|
||||
QString icon() {return m_icon;}
|
||||
QString value() {return m_value;}
|
||||
bool writable() {return m_writable;}
|
||||
bool visibleItem() {return m_visible;}
|
||||
QString plusName() {return m_id + "_plus";}
|
||||
QString minusName() {return m_id + "_minus";}
|
||||
|
||||
@@ -32,12 +35,14 @@ public:
|
||||
QString m_icon;
|
||||
QString m_value;
|
||||
bool m_writable;
|
||||
bool m_visible = true;
|
||||
|
||||
signals:
|
||||
void valueChanged(QString value);
|
||||
void nameChanged(QString value);
|
||||
void iconChanged(QString value);
|
||||
void writableChanged(bool value);
|
||||
void visibleChanged(bool value);
|
||||
void plusNameChanged(QString value);
|
||||
void minusNameChanged(QString value);
|
||||
};
|
||||
@@ -48,15 +53,18 @@ class homeform: public QObject
|
||||
Q_PROPERTY( bool device READ getDevice NOTIFY changeOfdevice)
|
||||
Q_PROPERTY( bool zwift READ getZwift NOTIFY changeOfzwift)
|
||||
Q_PROPERTY(QString info READ info NOTIFY infoChanged)
|
||||
Q_PROPERTY(QString signal READ signal NOTIFY signalChanged)
|
||||
|
||||
public:
|
||||
homeform(QQmlApplicationEngine* engine, bluetooth* bl);
|
||||
QString info() {return m_info;}
|
||||
QString signal();
|
||||
|
||||
private:
|
||||
QList<QObject *> dataList;
|
||||
QList<SessionLine> Session;
|
||||
bluetooth* bluetoothManager;
|
||||
bluetooth* bluetoothManager = 0;
|
||||
QQmlApplicationEngine* engine;
|
||||
|
||||
QString m_info = "Connecting...";
|
||||
|
||||
@@ -84,10 +92,12 @@ private slots:
|
||||
void Minus(QString);
|
||||
void Plus(QString);
|
||||
void deviceFound(QString name);
|
||||
void deviceConnected();
|
||||
|
||||
signals:
|
||||
void changeOfdevice();
|
||||
void changeOfzwift();
|
||||
void signalChanged(QString value);
|
||||
void infoChanged(QString value);
|
||||
};
|
||||
|
||||
|
||||
@@ -18,5 +18,9 @@
|
||||
<file>icons/pace.png</file>
|
||||
<file>icons/chart.png</file>
|
||||
<file>icons/icon.png</file>
|
||||
<file>icons/signal-0.png</file>
|
||||
<file>icons/signal-1.png</file>
|
||||
<file>icons/signal-2.png</file>
|
||||
<file>icons/signal-3.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
||||
BIN
src/icons/signal-0.png
Normal file
BIN
src/icons/signal-0.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 429 B |
BIN
src/icons/signal-1.png
Normal file
BIN
src/icons/signal-1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 423 B |
BIN
src/icons/signal-2.png
Normal file
BIN
src/icons/signal-2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 412 B |
BIN
src/icons/signal-3.png
Normal file
BIN
src/icons/signal-3.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 389 B |
29
src/main.cpp
29
src/main.cpp
@@ -2,9 +2,11 @@
|
||||
#include <QStyleFactory>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h> // getuid
|
||||
#include <QStandardPaths>
|
||||
#include <QGuiApplication>
|
||||
#include <QQmlApplicationEngine>
|
||||
#include <QtAndroid>
|
||||
#include "virtualtreadmill.h"
|
||||
#include "domyostreadmill.h"
|
||||
#include "bluetooth.h"
|
||||
@@ -143,18 +145,35 @@ void myMessageOutput(QtMsgType type, const QMessageLogContext &context, const QS
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
#ifdef Q_OS_LINUX
|
||||
#ifndef Q_OS_ANDROID
|
||||
if (getuid())
|
||||
{
|
||||
printf("Runme as root!\n");
|
||||
return -1;
|
||||
}
|
||||
else printf("%s", "OK, you are root.\n");
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef Q_OS_ANDROID
|
||||
QScopedPointer<QCoreApplication> app(createApplication(argc, argv));
|
||||
qInstallMessageHandler(myMessageOutput);
|
||||
#endif
|
||||
|
||||
qInstallMessageHandler(myMessageOutput);
|
||||
qDebug() << "version 1.0.1";
|
||||
|
||||
#ifndef Q_OS_ANDROID
|
||||
if(onlyVirtualBike)
|
||||
{
|
||||
virtualbike* V = new virtualbike(new bike(), noWriteResistance, noHeartService);
|
||||
Q_UNUSED(V)
|
||||
return app->exec();
|
||||
}
|
||||
else if(onlyVirtualTreadmill)
|
||||
{
|
||||
virtualtreadmill* V = new virtualtreadmill(new treadmill(), noHeartService);
|
||||
Q_UNUSED(V)
|
||||
return app->exec();
|
||||
}
|
||||
#endif
|
||||
@@ -170,6 +189,14 @@ int main(int argc, char *argv[])
|
||||
if (!obj && url == objUrl)
|
||||
QCoreApplication::exit(-1);
|
||||
}, Qt::QueuedConnection);
|
||||
|
||||
auto result = QtAndroid::checkPermission(QString("android.permission.WRITE_EXTERNAL_STORAGE"));
|
||||
if(result == QtAndroid::PermissionResult::Denied){
|
||||
QtAndroid::PermissionResultMap resultHash = QtAndroid::requestPermissionsSync(QStringList({"android.permission.WRITE_EXTERNAL_STORAGE"}));
|
||||
if(resultHash["android.permission.STORAGE"] == QtAndroid::PermissionResult::Denied)
|
||||
qDebug() << "log unwritable!";
|
||||
}
|
||||
|
||||
engine.load(url);
|
||||
new homeform(&engine, bl);
|
||||
|
||||
|
||||
@@ -65,8 +65,15 @@ void MainWindow::update()
|
||||
|
||||
if(bluetoothManager->device()->deviceType() == bluetoothdevice::TREADMILL)
|
||||
{
|
||||
pace = 10000 / (((treadmill*)bluetoothManager->device())->currentPace().second() + (((treadmill*)bluetoothManager->device())->currentPace().minute() * 60));
|
||||
if(pace < 0) pace = 0;
|
||||
if(bluetoothManager->device()->currentSpeed())
|
||||
{
|
||||
pace = 10000 / (((treadmill*)bluetoothManager->device())->currentPace().second() + (((treadmill*)bluetoothManager->device())->currentPace().minute() * 60));
|
||||
if(pace < 0) pace = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
pace = 0;
|
||||
}
|
||||
watts = ((treadmill*)bluetoothManager->device())->watts(ui->weight->text().toFloat());
|
||||
inclination = ((treadmill*)bluetoothManager->device())->currentInclination();
|
||||
ui->pace->setText(((treadmill*)bluetoothManager->device())->currentPace().toString("m:ss"));
|
||||
@@ -80,6 +87,7 @@ void MainWindow::update()
|
||||
watts = ((bike*)bluetoothManager->device())->watts();
|
||||
ui->watt->setText(QString::number(watts));
|
||||
ui->resistance->setText(QString::number(resistance));
|
||||
ui->cadence->setText(QString::number(((bike*)bluetoothManager->device())->currentCadence()));
|
||||
}
|
||||
|
||||
if(trainProgram)
|
||||
|
||||
@@ -20,10 +20,12 @@ SOURCES += \
|
||||
bluetoothdevice.cpp \
|
||||
charts.cpp \
|
||||
domyostreadmill.cpp \
|
||||
echelonconnectsport.cpp \
|
||||
gpx.cpp \
|
||||
homeform.cpp \
|
||||
main.cpp \
|
||||
sessionline.cpp \
|
||||
signalhandler.cpp \
|
||||
toorxtreadmill.cpp \
|
||||
treadmill.cpp \
|
||||
mainwindow.cpp \
|
||||
@@ -44,8 +46,10 @@ HEADERS += \
|
||||
bluetoothdevice.h \
|
||||
charts.h \
|
||||
domyostreadmill.h \
|
||||
echelonconnectsport.h \
|
||||
homeform.h \
|
||||
sessionline.h \
|
||||
signalhandler.h \
|
||||
toorxtreadmill.h \
|
||||
gpx.h \
|
||||
treadmill.h \
|
||||
|
||||
169
src/signalhandler.cpp
Normal file
169
src/signalhandler.cpp
Normal file
@@ -0,0 +1,169 @@
|
||||
#include "signalhandler.h"
|
||||
#include <assert.h>
|
||||
#include <cstddef>
|
||||
|
||||
#if 1
|
||||
|
||||
#include <signal.h>
|
||||
|
||||
#else
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#endif //!__MINGW32_MAJOR_VERSION
|
||||
|
||||
// There can be only ONE SignalHandler per process
|
||||
SignalHandler* g_handler(NULL);
|
||||
|
||||
#if 0
|
||||
|
||||
BOOL WINAPI WIN32_handleFunc(DWORD);
|
||||
int WIN32_physicalToLogical(DWORD);
|
||||
DWORD WIN32_logicalToPhysical(int);
|
||||
std::set<int> g_registry;
|
||||
|
||||
#else //__MINGW32_MAJOR_VERSION
|
||||
|
||||
void POSIX_handleFunc(int);
|
||||
int POSIX_physicalToLogical(int);
|
||||
int POSIX_logicalToPhysical(int);
|
||||
|
||||
#endif //__MINGW32_MAJOR_VERSION
|
||||
|
||||
SignalHandler::SignalHandler(int mask) : _mask(mask)
|
||||
{
|
||||
assert(g_handler == NULL);
|
||||
g_handler = this;
|
||||
|
||||
#if 0
|
||||
SetConsoleCtrlHandler(WIN32_handleFunc, TRUE);
|
||||
#endif //__MINGW32_MAJOR_VERSION
|
||||
|
||||
for (int i=0;i<numSignals;i++)
|
||||
{
|
||||
int logical = 0x1 << i;
|
||||
if (_mask & logical)
|
||||
{
|
||||
#if 0
|
||||
g_registry.insert(logical);
|
||||
#else
|
||||
int sig = POSIX_logicalToPhysical(logical);
|
||||
bool failed = signal(sig, POSIX_handleFunc) == SIG_ERR;
|
||||
assert(!failed);
|
||||
(void)failed; // Silence the warning in non _DEBUG; TODO: something better
|
||||
|
||||
#endif //__MINGW32_MAJOR_VERSION
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
SignalHandler::~SignalHandler()
|
||||
{
|
||||
#if 0
|
||||
SetConsoleCtrlHandler(WIN32_handleFunc, FALSE);
|
||||
#else
|
||||
for (int i=0;i<numSignals;i++)
|
||||
{
|
||||
int logical = 0x1 << i;
|
||||
if (_mask & logical)
|
||||
{
|
||||
signal(POSIX_logicalToPhysical(logical), SIG_DFL);
|
||||
}
|
||||
}
|
||||
#endif //__MINGW32_MAJOR_VERSION
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
DWORD WIN32_logicalToPhysical(int signal)
|
||||
{
|
||||
switch (signal)
|
||||
{
|
||||
case SignalHandler::SIG_INT: return CTRL_C_EVENT;
|
||||
case SignalHandler::SIG_TERM: return CTRL_BREAK_EVENT;
|
||||
case SignalHandler::SIG_CLOSE: return CTRL_CLOSE_EVENT;
|
||||
default:
|
||||
return ~(unsigned int)0; // SIG_ERR = -1
|
||||
}
|
||||
}
|
||||
#else
|
||||
int POSIX_logicalToPhysical(int signal)
|
||||
{
|
||||
switch (signal)
|
||||
{
|
||||
case SignalHandler::SIG_INT: return SIGINT;
|
||||
case SignalHandler::SIG_TERM: return SIGTERM;
|
||||
// In case the client asks for a SIG_CLOSE handler, accept and
|
||||
// bind it to a SIGTERM. Anyway the signal will never be raised
|
||||
case SignalHandler::SIG_CLOSE: return SIGTERM;
|
||||
//case SignalHandler::SIG_RELOAD: return SIGHUP;
|
||||
default:
|
||||
return -1; // SIG_ERR = -1
|
||||
}
|
||||
}
|
||||
#endif //__MINGW32_MAJOR_VERSION
|
||||
|
||||
|
||||
#if 0
|
||||
int WIN32_physicalToLogical(DWORD signal)
|
||||
{
|
||||
switch (signal)
|
||||
{
|
||||
case CTRL_C_EVENT: return SignalHandler::SIG_INT;
|
||||
case CTRL_BREAK_EVENT: return SignalHandler::SIG_TERM;
|
||||
case CTRL_CLOSE_EVENT: return SignalHandler::SIG_CLOSE;
|
||||
default:
|
||||
return SignalHandler::SIG_UNHANDLED;
|
||||
}
|
||||
}
|
||||
#else
|
||||
int POSIX_physicalToLogical(int signal)
|
||||
{
|
||||
switch (signal)
|
||||
{
|
||||
case SIGINT: return SignalHandler::SIG_INT;
|
||||
case SIGTERM: return SignalHandler::SIG_TERM;
|
||||
//case SIGHUP: return SignalHandler::SIG_RELOAD;
|
||||
default:
|
||||
return SignalHandler::SIG_UNHANDLED;
|
||||
}
|
||||
}
|
||||
#endif //__MINGW32_MAJOR_VERSION
|
||||
|
||||
|
||||
|
||||
#if 0
|
||||
BOOL WINAPI WIN32_handleFunc(DWORD signal)
|
||||
{
|
||||
if (g_handler)
|
||||
{
|
||||
int signo = WIN32_physicalToLogical(signal);
|
||||
// The std::set is thread-safe in const reading access and we never
|
||||
// write to it after the program has started so we don't need to
|
||||
// protect this search by a mutex
|
||||
std::set<int>::const_iterator found = g_registry.find(signo);
|
||||
if (signo != -1 && found != g_registry.end())
|
||||
{
|
||||
return g_handler->handleSignal(signo) ? TRUE : FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
#else
|
||||
void POSIX_handleFunc(int signal)
|
||||
{
|
||||
if (g_handler)
|
||||
{
|
||||
int signo = POSIX_physicalToLogical(signal);
|
||||
g_handler->handleSignal(signo);
|
||||
}
|
||||
}
|
||||
#endif //__MINGW32_MAJOR_VERSION
|
||||
29
src/signalhandler.h
Normal file
29
src/signalhandler.h
Normal file
@@ -0,0 +1,29 @@
|
||||
#ifndef SIGNALHANDLER_H
|
||||
#define SIGNALHANDLER_H
|
||||
|
||||
|
||||
class SignalHandler
|
||||
{
|
||||
public:
|
||||
SignalHandler(int mask = DEFAULT_SIGNALS);
|
||||
virtual ~SignalHandler();
|
||||
|
||||
enum SIGNALS
|
||||
{
|
||||
SIG_UNHANDLED = 0, // Physical signal not supported by this class
|
||||
SIG_NOOP = 1, // The application is requested to do a no-op (only a target that platform-specific signals map to when they can't be raised anyway)
|
||||
SIG_INT = 2, // Control+C (should terminate but consider that it's a normal way to do so; can delay a bit)
|
||||
SIG_TERM = 4, // Control+Break (should terminate now without regarding the consquences)
|
||||
SIG_CLOSE = 8, // Container window closed (should perform normal termination, like Ctrl^C) [Windows only; on Linux it maps to SIG_TERM]
|
||||
SIG_RELOAD = 16, // Reload the configuration [Linux only, physical signal is SIGHUP; on Windows it maps to SIG_NOOP]
|
||||
DEFAULT_SIGNALS = SIG_INT | SIG_TERM | SIG_CLOSE,
|
||||
};
|
||||
static const int numSignals = 6;
|
||||
|
||||
virtual bool handleSignal(int signal) = 0;
|
||||
|
||||
private:
|
||||
int _mask;
|
||||
};
|
||||
|
||||
#endif // SIGNALHANDLER_H
|
||||
@@ -15,7 +15,7 @@ void toorxtreadmill::deviceDiscovered(const QBluetoothDeviceInfo &device)
|
||||
debug("Found new device: " + device.name() + " (" + device.address().toString() + ')');
|
||||
if(device.name().startsWith("TRX ROUTE KEY"))
|
||||
{
|
||||
bttreadmill = device;
|
||||
bluetoothDevice = device;
|
||||
|
||||
// Create a discovery agent and connect to its signals
|
||||
discoveryAgent = new QBluetoothServiceDiscoveryAgent(this);
|
||||
@@ -31,7 +31,7 @@ void toorxtreadmill::deviceDiscovered(const QBluetoothDeviceInfo &device)
|
||||
// In your local slot, read information about the found devices
|
||||
void toorxtreadmill::serviceDiscovered(const QBluetoothServiceInfo &service)
|
||||
{
|
||||
if(service.device().address() == bttreadmill.address())
|
||||
if(service.device().address() == bluetoothDevice.address())
|
||||
{
|
||||
debug("Found new service: " + service.serviceName()
|
||||
+ '(' + service.serviceUuid().toString() + ')');
|
||||
|
||||
@@ -46,7 +46,6 @@ private slots:
|
||||
void update();
|
||||
|
||||
private:
|
||||
QBluetoothDeviceInfo bttreadmill;
|
||||
QBluetoothServiceDiscoveryAgent *discoveryAgent;
|
||||
QBluetoothServiceInfo serialPortService;
|
||||
QBluetoothSocket *socket = nullptr;
|
||||
|
||||
@@ -58,7 +58,7 @@ void trxappgateusbtreadmill::update()
|
||||
initRequest = false;
|
||||
btinit(false);
|
||||
}
|
||||
else if(bttreadmill.isValid() &&
|
||||
else if(bluetoothDevice.isValid() &&
|
||||
m_control->state() == QLowEnergyController::DiscoveredState &&
|
||||
gattCommunicationChannelService &&
|
||||
gattWriteCharacteristic.isValid() &&
|
||||
@@ -342,8 +342,8 @@ void trxappgateusbtreadmill::deviceDiscovered(const QBluetoothDeviceInfo &device
|
||||
debug("Found new device: " + device.name() + " (" + device.address().toString() + ')');
|
||||
if(device.name().startsWith("TOORX"))
|
||||
{
|
||||
bttreadmill = device;
|
||||
m_control = QLowEnergyController::createCentral(bttreadmill, this);
|
||||
bluetoothDevice = device;
|
||||
m_control = QLowEnergyController::createCentral(bluetoothDevice, this);
|
||||
connect(m_control, SIGNAL(serviceDiscovered(const QBluetoothUuid &)),
|
||||
this, SLOT(serviceDiscovered(const QBluetoothUuid &)));
|
||||
connect(m_control, SIGNAL(discoveryFinished()),
|
||||
|
||||
@@ -55,7 +55,6 @@ private:
|
||||
QTimer* refresh;
|
||||
virtualtreadmill* virtualTreadMill = 0;
|
||||
|
||||
QBluetoothDeviceInfo bttreadmill;
|
||||
QLowEnergyController* m_control = 0;
|
||||
QLowEnergyService* gattCommunicationChannelService = 0;
|
||||
QLowEnergyCharacteristic gattWriteCharacteristic;
|
||||
|
||||
Reference in New Issue
Block a user