Compare commits

...

22 Commits

Author SHA1 Message Date
Roberto Viola
2ef84e5798 Merge branch 'master' into nordictrack_usb 2025-02-03 16:13:19 +01:00
Roberto Viola
ff541371e1 trying to write only when i don't have a real answer 2023-07-28 21:35:32 +02:00
Roberto Viola
29789ea659 Merge branch 'master' into nordictrack_usb 2023-07-26 14:25:11 +02:00
Roberto Viola
234a10bcab Update nordictrackusbtreadmill.cpp 2023-07-26 14:22:18 +02:00
Roberto Viola
938c5673e8 Update nordictrackusbtreadmill.cpp 2023-07-25 16:48:10 +02:00
Roberto Viola
f9d62ee02c Update NordictrackUSBHID.java 2023-07-25 10:33:34 +02:00
Roberto Viola
a85ed1910f Update nordictrackusbtreadmill.h 2023-07-25 10:01:59 +02:00
Roberto Viola
1ca1a63aa3 build error 2023-07-25 09:37:11 +02:00
Roberto Viola
34312be8f4 debug log always enabled 2023-07-25 09:14:56 +02:00
Roberto Viola
60729e6b52 first commit 2023-07-25 09:11:25 +02:00
Roberto Viola
e48af4e864 Update main.yml 2023-07-20 17:39:50 +02:00
Roberto Viola
e990a27f65 Update main.yml 2023-07-20 16:15:17 +02:00
Roberto Viola
4c88304be0 Update main.yml 2023-07-20 16:14:21 +02:00
Roberto Viola
4c1d39d68c Update main.yml 2023-07-20 16:12:38 +02:00
Roberto Viola
efc92f72b2 Update main.yml 2023-07-20 14:37:13 +02:00
Roberto Viola
424e21a8fa Update main.yml 2023-07-20 14:03:14 +02:00
Roberto Viola
51bc2ffb48 Update main.yml 2023-07-20 12:00:28 +02:00
Roberto Viola
7cfd1ba93b Update main.yml 2023-07-20 11:58:34 +02:00
Roberto Viola
c01e5ccb14 Update main.yml 2023-07-20 11:49:08 +02:00
Roberto Viola
dd495f1a76 Merge branch 'master' into android_CI_googleplay 2023-07-20 11:48:52 +02:00
Roberto Viola
78e3a33596 Update main.yml 2023-07-20 11:23:17 +02:00
Roberto Viola
77a9fc718a Update main.yml 2023-07-20 11:13:54 +02:00
8 changed files with 619 additions and 3 deletions

View File

@@ -29,6 +29,9 @@
<usb-device vendor-id="17A4" product-id="0002" />
<usb-device vendor-id="17A4" product-id="0001" />
<!-- ICON Fitness, Nordictrack treadmill -->
<usb-device vendor-id="213c" product-id="0002" />
<!-- CDC driver -->
<usb-device vendor-id="9025" /> <!-- 0x2341 / ......: Arduino -->
<usb-device vendor-id="5824" product-id="1155" /> <!-- 0x16C0 / 0x0483: Teensyduino -->

View File

@@ -0,0 +1,66 @@
package org.cagnulen.qdomyoszwift;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Set;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Deque;
import java.util.EnumSet;
import java.util.concurrent.Callable;
import java.util.ArrayList;
import java.util.List;
import java.nio.charset.StandardCharsets;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbEndpoint;
import android.hardware.usb.UsbInterface;
import android.hardware.usb.UsbManager;
import android.util.Log;
public class NordictrackUSBHID {
static HidBridge hidBridge;
static byte[] receiveData;
static int lastReadLen = 0;
public static void open(Context context) {
Log.d("QZ","NordictrackUSBHID open");
hidBridge = new HidBridge(context, 0x0002, 0x213c);
boolean ret = hidBridge.OpenDevice();
Log.d("QZ","hidBridge.OpenDevice " + ret);
hidBridge.StartReadingThread();
Log.d("QZ","hidBridge.StartReadingThread");
}
public static void write (byte[] bytes) {
Log.d("QZ","NordictrackUSBHID writing " + new String(bytes, StandardCharsets.ISO_8859_1));
hidBridge.WriteData(bytes);
}
public static int readLen() {
return lastReadLen;
}
public static byte[] read() {
if(hidBridge.IsThereAnyReceivedData()) {
receiveData = hidBridge.GetReceivedDataFromQueue();
lastReadLen = receiveData.length;
Log.d("QZ","NordictrackUSBHID reading " + lastReadLen + new String(receiveData, StandardCharsets.ISO_8859_1));
return receiveData;
} else {
Log.d("QZ","NordictrackUSBHID empty data");
lastReadLen = 0;
return null;
}
}
}

View File

@@ -56,6 +56,10 @@ bluetooth::bluetooth(bool logs, const QString &deviceName, bool noWriteResistanc
connectedAndDiscovered();
return;
#endif
nordictrackusbTreadmill = new nordictrackusbtreadmill(false, false, false);
this->signalBluetoothDeviceConnected(nordictrackusbTreadmill);
connectedAndDiscovered();
return;
if (!startDiscovery) {
this->discoveryAgent = nullptr;
@@ -3171,6 +3175,11 @@ void bluetooth::restart() {
delete proformWifiTreadmill;
proformWifiTreadmill = nullptr;
}
if (nordictrackusbTreadmill) {
delete nordictrackusbTreadmill;
nordictrackusbTreadmill = nullptr;
}
if (nordictrackifitadbTreadmill) {
delete nordictrackifitadbTreadmill;
@@ -3649,6 +3658,8 @@ bluetoothdevice *bluetooth::device() {
return proformTelnetBike;
} else if (proformWifiTreadmill) {
return proformWifiTreadmill;
} else if (nordictrackusbTreadmill) {
return nordictrackusbTreadmill;
} else if (antBike) {
return antBike;
} else if (nordictrackifitadbTreadmill) {

View File

@@ -56,7 +56,7 @@
#include "devices/faketreadmill/faketreadmill.h"
#include "devices/fitmetria_fanfit/fitmetria_fanfit.h"
#include "devices/fitplusbike/fitplusbike.h"
#include "nordictrackusbtreadmill.h"
#include "devices/fitshowtreadmill/fitshowtreadmill.h"
#include "devices/flywheelbike/flywheelbike.h"
#include "devices/ftmsbike/ftmsbike.h"
@@ -210,6 +210,7 @@ class bluetooth : public QObject, public SignalHandler {
flywheelbike *flywheelBike = nullptr;
nordictrackelliptical *nordictrackElliptical = nullptr;
nordictrackifitadbtreadmill *nordictrackifitadbTreadmill = nullptr;
nordictrackusbtreadmill *nordictrackusbTreadmill = nullptr;
nordictrackifitadbbike *nordictrackifitadbBike = nullptr;
nordictrackifitadbelliptical *nordictrackifitadbElliptical = nullptr;
octaneelliptical *octaneElliptical = nullptr;

View File

@@ -263,8 +263,8 @@ QCoreApplication *createApplication(int &argc, char *argv[]) {
void myMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg) {
QSettings settings;
static bool logdebug = settings.value(QZSettings::log_debug, QZSettings::default_log_debug).toBool();
#if defined(Q_OS_LINUX) // Linux OS does not read settings file for now
static bool logdebug = true; // settings.value(QZSettings::log_debug, QZSettings::default_log_debug).toBool();
#if defined(Q_OS_LINUX) // Linux OS does not read settings file for now
if ((logs == false && !forceQml) || (logdebug == false && forceQml))
#else
if (logdebug == false)

View File

@@ -0,0 +1,377 @@
#include "nordictrackusbtreadmill.h"
using namespace std::chrono_literals;
nordictrackusbtreadmill::nordictrackusbtreadmill(bool noWriteResistance, bool noHeartService, bool noVirtualDevice) {
m_watt.setType(metric::METRIC_WATT);
Speed.setType(metric::METRIC_SPEED);
refresh = new QTimer(this);
this->noWriteResistance = noWriteResistance;
this->noHeartService = noHeartService;
this->noVirtualDevice = noVirtualDevice;
initDone = false;
connect(refresh, &QTimer::timeout, this, &nordictrackusbtreadmill::update);
refresh->start(200ms);
nordictrackusbtreadmillThread *t = new nordictrackusbtreadmillThread();
t->start();
}
nordictrackusbtreadmillThread::nordictrackusbtreadmillThread() {}
void nordictrackusbtreadmillThread::run() {
QSettings settings;
/*devicePort =
settings.value(QZSettings::computrainer_serialport, QZSettings::default_computrainer_serialport).toString();*/
openPort();
int countError = 0;
while (1) {
uint8_t command[64];
memset(command, 0xFF, sizeof(command));
if(countError == 0)
rawWrite(command, sizeof(command));
static uint8_t rx[100];
memset(rx, 0x00, sizeof(rx));
rawRead(rx, 100);
qDebug() << " << " << QByteArray::fromRawData((const char *)rx, 64).toHex(' ');
QThread::msleep(50);
if(countError++>10)
countError = 0;
}
closePort();
}
int nordictrackusbtreadmillThread::closePort() {
#ifdef WIN32
return (int)!CloseHandle(devicePort);
#else
tcflush(devicePort, TCIOFLUSH); // clear out the garbage
return close(devicePort);
#endif
}
int nordictrackusbtreadmillThread::openPort() {
#ifdef Q_OS_ANDROID
QAndroidJniObject::callStaticMethod<void>("org/cagnulen/qdomyoszwift/NordictrackUSBHID", "open",
"(Landroid/content/Context;)V", QtAndroid::androidContext().object());
#elif !defined(WIN32)
// LINUX AND MAC USES TERMIO / IOCTL / STDIO
#if defined(Q_OS_MACX)
int ldisc = TTYDISC;
#else
int ldisc = N_TTY; // LINUX
#endif
if ((devicePort = open(deviceFilename.toLatin1(), O_RDWR | O_NOCTTY | O_NONBLOCK)) == -1)
return errno;
tcflush(devicePort, TCIOFLUSH); // clear out the garbage
if (ioctl(devicePort, TIOCSETD, &ldisc) == -1)
return errno;
// get current settings for the port
tcgetattr(devicePort, &deviceSettings);
// set raw mode i.e. ignbrk, brkint, parmrk, istrip, inlcr, igncr, icrnl, ixon
// noopost, cs8, noecho, noechonl, noicanon, noisig, noiexn
cfmakeraw(&deviceSettings);
cfsetspeed(&deviceSettings, B2400);
// further attributes
deviceSettings.c_iflag &=
~(IGNBRK | BRKINT | ICRNL | INLCR | PARMRK | INPCK | ICANON | ISTRIP | IXON | IXOFF | IXANY);
deviceSettings.c_iflag |= IGNPAR;
deviceSettings.c_cflag &= (~CSIZE & ~CSTOPB);
deviceSettings.c_oflag = 0;
#if defined(Q_OS_MACX)
deviceSettings.c_cflag &= (~CCTS_OFLOW & ~CRTS_IFLOW); // no hardware flow control
deviceSettings.c_cflag |= (CS8 | CLOCAL | CREAD | HUPCL);
#else
deviceSettings.c_cflag &= (~CRTSCTS); // no hardware flow control
deviceSettings.c_cflag |= (CS8 | CLOCAL | CREAD | HUPCL);
#endif
deviceSettings.c_lflag = 0;
deviceSettings.c_cc[VSTART] = 0x11;
deviceSettings.c_cc[VSTOP] = 0x13;
deviceSettings.c_cc[VEOF] = 0x20;
deviceSettings.c_cc[VMIN] = 0;
deviceSettings.c_cc[VTIME] = 0;
// set those attributes
if (tcsetattr(devicePort, TCSANOW, &deviceSettings) == -1)
return errno;
tcgetattr(devicePort, &deviceSettings);
tcflush(devicePort, TCIOFLUSH); // clear out the garbage
#else
// WINDOWS USES SET/GETCOMMSTATE AND READ/WRITEFILE
COMMTIMEOUTS timeouts; // timeout settings on serial ports
// if deviceFilename references a port above COM9
// then we need to open "\\.\COMX" not "COMX"
QString portSpec;
int portnum = deviceFilename.midRef(3).toString().toInt();
if (portnum < 10)
portSpec = deviceFilename;
else
portSpec = "\\\\.\\" + deviceFilename;
wchar_t deviceFilenameW[32]; // \\.\COM32 needs 9 characters, 32 should be enough?
MultiByteToWideChar(CP_ACP, 0, portSpec.toLatin1(), -1, (LPWSTR)deviceFilenameW, sizeof(deviceFilenameW));
// win32 commport API
devicePort = CreateFile(deviceFilenameW, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_DELETE | FILE_SHARE_WRITE | FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if (devicePort == INVALID_HANDLE_VALUE)
return -1;
if (GetCommState(devicePort, &deviceSettings) == false)
return -1;
// so we've opened the comm port lets set it up for
deviceSettings.BaudRate = CBR_2400;
deviceSettings.fParity = NOPARITY;
deviceSettings.ByteSize = 8;
deviceSettings.StopBits = ONESTOPBIT;
deviceSettings.XonChar = 11;
deviceSettings.XoffChar = 13;
deviceSettings.EofChar = 0x0;
deviceSettings.ErrorChar = 0x0;
deviceSettings.EvtChar = 0x0;
deviceSettings.fBinary = true;
deviceSettings.fOutX = 0;
deviceSettings.fInX = 0;
deviceSettings.XonLim = 0;
deviceSettings.XoffLim = 0;
deviceSettings.fRtsControl = RTS_CONTROL_ENABLE;
deviceSettings.fDtrControl = DTR_CONTROL_ENABLE;
deviceSettings.fOutxCtsFlow = FALSE; // TRUE;
if (SetCommState(devicePort, &deviceSettings) == false) {
CloseHandle(devicePort);
return -1;
}
timeouts.ReadIntervalTimeout = 0;
timeouts.ReadTotalTimeoutConstant = 1000;
timeouts.ReadTotalTimeoutMultiplier = 50;
timeouts.WriteTotalTimeoutConstant = 2000;
timeouts.WriteTotalTimeoutMultiplier = 0;
SetCommTimeouts(devicePort, &timeouts);
#endif
// success
return 0;
}
int nordictrackusbtreadmillThread::rawWrite(uint8_t *bytes, int size) // unix!!
{
qDebug() << size << QByteArray((const char *)bytes, size).toHex(' ');
int rc = 0;
#ifdef Q_OS_ANDROID
QAndroidJniEnvironment env;
jbyteArray d = env->NewByteArray(size);
jbyte *b = env->GetByteArrayElements(d, 0);
for (int i = 0; i < size; i++)
b[i] = bytes[i];
env->SetByteArrayRegion(d, 0, size, b);
QAndroidJniObject::callStaticMethod<void>("org/cagnulen/qdomyoszwift/NordictrackUSBHID", "write", "([B)V", d);
#elif defined(WIN32)
DWORD cBytes;
rc = WriteFile(devicePort, bytes, size, &cBytes, NULL);
if (!rc)
return -1;
return rc;
#else
int ibytes;
ioctl(devicePort, FIONREAD, &ibytes);
// timeouts are less critical for writing, since vols are low
rc = write(devicePort, bytes, size);
// but it is good to avoid buffer overflow since the
// computrainer microcontroller has almost no RAM
if (rc != -1)
tcdrain(devicePort); // wait till its gone.
ioctl(devicePort, FIONREAD, &ibytes);
#endif
return rc;
}
int nordictrackusbtreadmillThread::rawRead(uint8_t bytes[], int size) {
int rc = 0;
#ifdef Q_OS_ANDROID
int64_t start = QDateTime::currentMSecsSinceEpoch();
jint len = 0;
do {
QAndroidJniEnvironment env;
QAndroidJniObject dd =
QAndroidJniObject::callStaticObjectMethod("org/cagnulen/qdomyoszwift/NordictrackUSBHID", "read", "()[B");
len =
QAndroidJniObject::callStaticMethod<jint>("org/cagnulen/qdomyoszwift/NordictrackUSBHID", "readLen", "()I");
if (len > 0) {
jbyteArray d = dd.object<jbyteArray>();
jbyte *b = env->GetByteArrayElements(d, 0);
for (int i = 0; i < len; i++) {
bytes[i] = b[i];
}
qDebug() << len << QByteArray((const char *)b, len).toHex(' ');
}
} while (len == 0 && start + 2000 > QDateTime::currentMSecsSinceEpoch());
return len;
#elif defined(WIN32)
Q_UNUSED(size);
// Readfile deals with timeouts and readyread issues
DWORD cBytes;
rc = ReadFile(devicePort, bytes, 7, &cBytes, NULL);
if (rc)
return (int)cBytes;
else
return (-1);
#else
int timeout = 0, i = 0;
uint8_t byte;
// read one byte at a time sleeping when no data ready
// until we timeout waiting then return error
for (i = 0; i < size; i++) {
timeout = 0;
rc = 0;
while (rc == 0 && timeout < CT_READTIMEOUT) {
rc = read(devicePort, &byte, 1);
if (rc == -1)
return -1; // error!
else if (rc == 0) {
msleep(50); // sleep for 1/20th of a second
timeout += 50;
} else {
bytes[i] = byte;
}
}
if (timeout >= CT_READTIMEOUT)
return -1; // we timed out!
}
qDebug() << i << QString::fromLocal8Bit((const char *)bytes, i);
return i;
#endif
}
void nordictrackusbtreadmill::update() {
QSettings settings;
QString heartRateBeltName =
settings.value(QZSettings::heart_rate_belt_name, QZSettings::default_heart_rate_belt_name).toString();
// update_metrics(false, watts());
Distance += ((Speed.value() / (double)3600.0) /
((double)1000.0 / (double)(lastRefreshCharacteristicChanged.msecsTo(QDateTime::currentDateTime()))));
lastRefreshCharacteristicChanged = QDateTime::currentDateTime();
// ******************************************* virtual bike/rower init *************************************
if (!firstStateChanged && !this->hasVirtualDevice()
#ifdef Q_OS_IOS
#ifndef IO_UNDER_QT
&& !h
#endif
#endif
) {
QSettings settings;
bool virtual_device_enabled =
settings.value(QZSettings::virtual_device_enabled, QZSettings::default_virtual_device_enabled).toBool();
bool virtual_device_rower =
settings.value(QZSettings::virtual_device_rower, QZSettings::default_virtual_device_rower).toBool();
#ifdef Q_OS_IOS
#ifndef IO_UNDER_QT
bool cadence =
settings.value(QZSettings::bike_cadence_sensor, QZSettings::default_bike_cadence_sensor).toBool();
bool ios_peloton_workaround =
settings.value(QZSettings::ios_peloton_workaround, QZSettings::default_ios_peloton_workaround).toBool();
if (ios_peloton_workaround && cadence && !virtual_device_rower) {
qDebug() << "ios_peloton_workaround activated!";
h = new lockscreen();
h->virtualbike_ios();
} else
#endif
#endif
if (virtual_device_enabled) {
if (!virtual_device_rower) {
qDebug() << QStringLiteral("creating virtual bike interface...");
auto virtualBike = new virtualbike(this, noWriteResistance, noHeartService);
// connect(virtualBike,&virtualbike::debug ,this,&echelonrower::debug);
this->setVirtualDevice(virtualBike, VIRTUAL_DEVICE_MODE::PRIMARY);
}
}
}
if (!firstStateChanged)
emit connectedAndDiscovered();
firstStateChanged = 1;
// ********************************************************************************************************
if (!noVirtualDevice) {
#ifdef Q_OS_ANDROID
if (settings.value(QZSettings::ant_heart, QZSettings::default_ant_heart).toBool()) {
Heart = (uint8_t)KeepAwakeHelper::heart();
debug("Current Heart: " + QString::number(Heart.value()));
}
#endif
if (heartRateBeltName.startsWith(QStringLiteral("Disabled"))) {
update_hr_from_external();
}
#ifdef Q_OS_IOS
#ifndef IO_UNDER_QT
bool cadence =
settings.value(QZSettings::bike_cadence_sensor, QZSettings::default_bike_cadence_sensor).toBool();
bool ios_peloton_workaround =
settings.value(QZSettings::ios_peloton_workaround, QZSettings::default_ios_peloton_workaround).toBool();
if (ios_peloton_workaround && cadence && h && firstStateChanged) {
h->virtualbike_setCadence(currentCrankRevolutions(), lastCrankEventTime());
h->virtualbike_setHeartRate((uint8_t)metrics_override_heartrate());
}
#endif
#endif
}
/*
if (Heart.value()) {
static double lastKcal = 0;
if (KCal.value() < 0) // if the user pressed stop, the KCAL resets the accumulator
lastKcal = abs(KCal.value());
KCal = metric::calculateKCalfromHR(Heart.average(), elapsed.value()) + lastKcal;
}*/
}
void nordictrackusbtreadmill::ftmsCharacteristicChanged(const QLowEnergyCharacteristic &characteristic,
const QByteArray &newValue) {
QByteArray b = newValue;
qDebug() << "routing FTMS packet to the bike from virtualbike" << characteristic.uuid() << newValue.toHex(' ');
}
bool nordictrackusbtreadmill::connected() { return true; }
void nordictrackusbtreadmill::deviceDiscovered(const QBluetoothDeviceInfo &device) {
emit debug(QStringLiteral("Found new device: ") + device.name() + " (" + device.address().toString() + ')');
}
void nordictrackusbtreadmill::newPacket(QByteArray p) {}

View File

@@ -0,0 +1,154 @@
#ifndef NORDICTRACKUSBTREADMILL_H
#define NORDICTRACKUSBTREADMILL_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 <QString>
#include "treadmill.h"
#include "virtualbike.h"
#include "virtualtreadmill.h"
#include <QDebug>
#include <QFile>
#include <QMutex>
#include <QSettings>
#include <QThread>
#ifdef WIN32
#include <windef.h>
#endif
#ifdef WIN32
#include <winbase.h>
#include <windows.h>
#else
#include <sys/ioctl.h>
#include <termios.h> // unix!!
#include <unistd.h> // unix!!
#ifndef N_TTY // for OpenBSD, this is a hack XXX
#define N_TTY 0
#endif
#endif
#ifdef Q_OS_ANDROID
#include "keepawakehelper.h"
#include <QAndroidJniObject>
#endif
#include <errno.h>
#include <fcntl.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#ifdef Q_OS_IOS
#include "ios/lockscreen.h"
#endif
/* read timeouts in microseconds */
#define CT_READTIMEOUT 1000
#define CT_WRITETIMEOUT 2000
class nordictrackusbtreadmillThread : public QThread {
Q_OBJECT
public:
explicit nordictrackusbtreadmillThread();
void run();
signals:
private:
// Utility and BG Thread functions
int openPort();
int closePort();
// Mutex for controlling accessing private data
QMutex pvars;
// device port
QString deviceFilename;
#ifdef WIN32
HANDLE devicePort; // file descriptor for reading from com3
DCB deviceSettings; // serial port settings baud rate et al
#else
int devicePort; // unix!!
struct termios deviceSettings; // unix!!
#endif
// raw device utils
int rawWrite(uint8_t *bytes, int size); // unix!!
int rawRead(uint8_t *bytes, int size); // unix!!
#ifdef Q_OS_ANDROID
QList<jbyte> bufRX;
bool cleanFrame = false;
#endif
};
class nordictrackusbtreadmill : public treadmill {
Q_OBJECT
public:
nordictrackusbtreadmill(bool noWriteResistance, bool noHeartService, bool noVirtualDevice);
bool connected() override;
private:
QTimer *refresh;
uint8_t sec1Update = 0;
QByteArray lastPacket;
QDateTime lastRefreshCharacteristicChanged = QDateTime::currentDateTime();
QDateTime lastGoodCadence = QDateTime::currentDateTime();
uint8_t firstStateChanged = 0;
bool initDone = false;
bool initRequest = false;
bool noWriteResistance = false;
bool noHeartService = false;
bool noVirtualDevice = false;
uint16_t oldLastCrankEventTime = 0;
uint16_t oldCrankRevs = 0;
#ifdef Q_OS_IOS
lockscreen *h = 0;
#endif
signals:
void disconnected();
void debug(QString string);
private slots:
void update();
void newPacket(QByteArray p);
void ftmsCharacteristicChanged(const QLowEnergyCharacteristic &characteristic, const QByteArray &newValue);
public slots:
void deviceDiscovered(const QBluetoothDeviceInfo &device);
};
#endif // NORDICTRACKUSBTREADMILL_H

View File

@@ -80,6 +80,7 @@ SOURCES += \
$$PWD/devices/cycleopsphantombike/cycleopsphantombike.cpp \
$$PWD/devices/deeruntreadmill/deerruntreadmill.cpp \
$$PWD/devices/focustreadmill/focustreadmill.cpp \
$$PWD/nordictrackusbtreadmill.cpp \
$$PWD/devices/jumprope.cpp \
$$PWD/devices/kineticinroadbike/SmartControl.cpp \
$$PWD/devices/kineticinroadbike/kineticinroadbike.cpp \
@@ -346,6 +347,7 @@ HEADERS += \
$$PWD/devices/sportstechelliptical/sportstechelliptical.h \
$$PWD/devices/sramAXSController/sramAXSController.h \
$$PWD/devices/technogymbike/technogymbike.h \
$$PWD/nordictrackusbtreadmill.h \
$$PWD/devices/trxappgateusbelliptical/trxappgateusbelliptical.h \
$$PWD/devices/trxappgateusbrower/trxappgateusbrower.h \
$$PWD/ergtable.h \
@@ -831,6 +833,7 @@ DISTFILES += \
$$PWD/android/libs/zaplibrary-debug.aar \
$$PWD/android/res/xml/device_filter.xml \
$$PWD/android/src/BleAdvertiser.java \
$$PWD/android/src/NordictrackUSBHID.java \
$$PWD/android/src/CSafeRowerUSBHID.java \
$$PWD/android/src/ContentHelper.java \
$$PWD/android/src/Garmin.java \
@@ -839,6 +842,7 @@ DISTFILES += \
$$PWD/android/src/LocationHelper.java \
$$PWD/android/src/MediaButtonReceiver.java \
$$PWD/android/src/MediaProjection.java \
$$PWD/android/src/NordictrackUSBHID.java \
$$PWD/android/src/NotificationUtils.java \
$$PWD/android/src/ScreenCaptureService.java \
$$PWD/android/src/Shortcuts.java \