Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,6 @@
87646C2227B5065100F82131 /* moc_bhfitnesselliptical.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 87646C2127B5065100F82131 /* moc_bhfitnesselliptical.cpp */; };
8767CA552DA3C1FD0003001F /* elitesquarecontroller.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 8767CA532DA3C1FD0003001F /* elitesquarecontroller.cpp */; };
8767CA562DA3C1FD0003001F /* moc_elitesquarecontroller.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 8767CA542DA3C1FD0003001F /* moc_elitesquarecontroller.cpp */; };
8767CA5D2DA7F5170003001F /* ios_wahookickrsnapbike.mm in Compile Sources */ = {isa = PBXBuildFile; fileRef = 8767CA5C2DA7F5170003001F /* ios_wahookickrsnapbike.mm */; };
8767CA602DA800590003001F /* ios_zwiftclickremote.mm in Compile Sources */ = {isa = PBXBuildFile; fileRef = 8767CA5F2DA800590003001F /* ios_zwiftclickremote.mm */; };
8767EF1E29448D6700810C0F /* characteristicwriteprocessor.cpp in Compile Sources */ = {isa = PBXBuildFile; fileRef = 8767EF1D29448D6700810C0F /* characteristicwriteprocessor.cpp */; };
8768C8BA2BBC11C80099DBE1 /* file_sync_client.c in Compile Sources */ = {isa = PBXBuildFile; fileRef = 8768C89C2BBC11C70099DBE1 /* file_sync_client.c */; };
Expand Down Expand Up @@ -1273,8 +1272,6 @@
8767CA522DA3C1FD0003001F /* elitesquarecontroller.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = elitesquarecontroller.h; path = ../src/devices/elitesquarecontroller/elitesquarecontroller.h; sourceTree = SOURCE_ROOT; };
8767CA532DA3C1FD0003001F /* elitesquarecontroller.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; name = elitesquarecontroller.cpp; path = ../src/devices/elitesquarecontroller/elitesquarecontroller.cpp; sourceTree = SOURCE_ROOT; };
8767CA542DA3C1FD0003001F /* moc_elitesquarecontroller.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = moc_elitesquarecontroller.cpp; sourceTree = "<group>"; };
8767CA5B2DA7F5170003001F /* ios_wahookickrsnapbike.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ios_wahookickrsnapbike.h; path = ../src/ios/ios_wahookickrsnapbike.h; sourceTree = SOURCE_ROOT; };
8767CA5C2DA7F5170003001F /* ios_wahookickrsnapbike.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = ios_wahookickrsnapbike.mm; path = ../src/ios/ios_wahookickrsnapbike.mm; sourceTree = SOURCE_ROOT; };
8767CA5E2DA800590003001F /* ios_zwiftclickremote.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ios_zwiftclickremote.h; path = ../src/ios/ios_zwiftclickremote.h; sourceTree = SOURCE_ROOT; };
8767CA5F2DA800590003001F /* ios_zwiftclickremote.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; name = ios_zwiftclickremote.mm; path = ../src/ios/ios_zwiftclickremote.mm; sourceTree = SOURCE_ROOT; };
8767EF1D29448D6700810C0F /* characteristicwriteprocessor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = characteristicwriteprocessor.cpp; path = ../src/characteristics/characteristicwriteprocessor.cpp; sourceTree = "<group>"; };
Expand Down Expand Up @@ -2376,8 +2373,6 @@
87F1BD702DC0D59600416506 /* moc_coresensor.cpp */,
8767CA5E2DA800590003001F /* ios_zwiftclickremote.h */,
8767CA5F2DA800590003001F /* ios_zwiftclickremote.mm */,
8767CA5B2DA7F5170003001F /* ios_wahookickrsnapbike.h */,
8767CA5C2DA7F5170003001F /* ios_wahookickrsnapbike.mm */,
87BFEA2D2CEDDEEE00BDD759 /* ios_echelonconnectsport.h */,
87BFEA2E2CEDDEEE00BDD759 /* ios_echelonconnectsport.mm */,
8767CA522DA3C1FD0003001F /* elitesquarecontroller.h */,
Expand Down Expand Up @@ -3894,7 +3889,6 @@
87EFB56E25BD703D0039DD5A /* proformtreadmill.cpp in Compile Sources */,
87DA8465284933D200B550E9 /* fakeelliptical.cpp in Compile Sources */,
876E50F52B701C050080FAAF /* moc_zwiftclickremote.cpp in Compile Sources */,
8767CA5D2DA7F5170003001F /* ios_wahookickrsnapbike.mm in Compile Sources */,
87FE5BAF2692F3130056EFC8 /* tacxneo2.cpp in Compile Sources */,
8718CBAC263063CE004BF4EE /* moc_tcpclientinfosender.cpp in Compile Sources */,
873824B527E64707004F1B46 /* moc_provider_p.cpp in Compile Sources */,
Expand Down
93 changes: 76 additions & 17 deletions src/devices/domyostreadmill/domyostreadmill.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,50 +73,98 @@ domyostreadmill::domyostreadmill(uint32_t pollDeviceTime, bool noConsole, bool n
initDone = false;
connect(refresh, &QTimer::timeout, this, &domyostreadmill::update);
refresh->start(pollDeviceTime);

// Initialize write timeout timer
writeTimeoutTimer = new QTimer(this);
writeTimeoutTimer->setSingleShot(true);
connect(writeTimeoutTimer, &QTimer::timeout, this, [this]() {
qDebug() << QStringLiteral("writeCharacteristic timeout - processing next in queue");
isWriting = false;
currentWriteWaitingForResponse = false;
processWriteQueue();
});

// Connect packetReceived signal to handle wait_for_response = true case
connect(this, &domyostreadmill::packetReceived, this, [this]() {
// Only process if we were waiting for a response
if (currentWriteWaitingForResponse && isWriting) {
// Stop timeout timer
writeTimeoutTimer->stop();

// Mark writing as complete and process next item in queue
isWriting = false;
currentWriteWaitingForResponse = false;
processWriteQueue();
}
});
}

void domyostreadmill::writeCharacteristic(uint8_t *data, uint8_t data_len, const QString &info, bool disable_log,
bool wait_for_response) {
QEventLoop loop;
QTimer timeout;
// Create write request and add to queue
WriteRequest request;
request.data = QByteArray((const char *)data, data_len);
request.info = info;
request.disable_log = disable_log;
request.wait_for_response = wait_for_response;

if (wait_for_response) {
connect(this, &domyostreadmill::packetReceived, &loop, &QEventLoop::quit);
timeout.singleShot(300ms, &loop, &QEventLoop::quit);
} else {
connect(gattCommunicationChannelService, &QLowEnergyService::characteristicWritten, &loop, &QEventLoop::quit);
timeout.singleShot(300ms, &loop, &QEventLoop::quit);
writeQueue.enqueue(request);

// Start processing if not already writing
processWriteQueue();
}

void domyostreadmill::processWriteQueue() {
// If already writing or queue is empty, do nothing
if (isWriting || writeQueue.isEmpty()) {
return;
}

if (gattCommunicationChannelService->state() != QLowEnergyService::ServiceState::ServiceDiscovered ||
// Check connection state
if (!gattCommunicationChannelService ||
gattCommunicationChannelService->state() != QLowEnergyService::ServiceState::ServiceDiscovered ||
m_control->state() == QLowEnergyController::UnconnectedState) {
qDebug() << QStringLiteral("writeCharacteristic error because the connection is closed");

// Clear the queue on disconnection
writeQueue.clear();
isWriting = false;
return;
}

if (!gattWriteCharacteristic.isValid()) {
qDebug() << QStringLiteral("gattWriteCharacteristic is invalid");
// Clear the queue on invalid characteristic
writeQueue.clear();
isWriting = false;
return;
}

// Get next request from queue
WriteRequest request = writeQueue.dequeue();
isWriting = true;
currentWriteWaitingForResponse = request.wait_for_response;

// Update write buffer
if (writeBuffer) {
delete writeBuffer;
}
writeBuffer = new QByteArray((const char *)data, data_len);
writeBuffer = new QByteArray(request.data);

// Write the characteristic
gattCommunicationChannelService->writeCharacteristic(gattWriteCharacteristic, *writeBuffer);

if (!disable_log) {
if (!request.disable_log) {
qDebug() << QStringLiteral(" >> ") + writeBuffer->toHex(' ')
<< QStringLiteral(" // ") + info;
<< QStringLiteral(" // ") + request.info;
}

loop.exec();
// Start timeout timer (300ms as before)
writeTimeoutTimer->start(300);

if (timeout.isActive() == false) {
qDebug() << QStringLiteral(" exit for timeout");
}
// Note: The actual completion will be signaled by:
// - characteristicWritten (if wait_for_response = false)
// - packetReceived (if wait_for_response = true)
// which will call processWriteQueue() again to process the next item
}

void domyostreadmill::updateDisplay(uint16_t elapsed) {
Expand Down Expand Up @@ -838,6 +886,17 @@ void domyostreadmill::characteristicWritten(const QLowEnergyCharacteristic &char
const QByteArray &newValue) {
Q_UNUSED(characteristic);
emit debug(QStringLiteral("characteristicWritten ") + newValue.toHex(' '));

// If the current write is NOT waiting for a response, we can process the next one
if (!currentWriteWaitingForResponse) {
// Stop timeout timer
writeTimeoutTimer->stop();

// Mark writing as complete and process next item in queue
isWriting = false;
processWriteQueue();
}
// Otherwise, we need to wait for packetReceived signal
}

void domyostreadmill::serviceScanDone(void) {
Expand Down
15 changes: 15 additions & 0 deletions src/devices/domyostreadmill/domyostreadmill.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include <QtCore/qmutex.h>
#include <QtCore/qscopedpointer.h>
#include <QtCore/qtimer.h>
#include <QtCore/qqueue.h>

#include <QDateTime>
#include <QObject>
Expand All @@ -43,6 +44,13 @@ class domyostreadmill : public treadmill {
bool changeFanSpeed(uint8_t speed) override;

private:
// Structure for async write queue
struct WriteRequest {
QByteArray data;
QString info;
bool disable_log;
bool wait_for_response;
};
bool sendChangeFanSpeed(uint8_t speed);
double GetSpeedFromPacket(const QByteArray &packet);
double GetInclinationFromPacket(const QByteArray &packet);
Expand All @@ -53,6 +61,7 @@ class domyostreadmill : public treadmill {
void btinit(bool startTape);
void writeCharacteristic(uint8_t *data, uint8_t data_len, const QString &info, bool disable_log = false,
bool wait_for_response = false);
void processWriteQueue();
void startDiscover();
volatile bool incompletePackets = false;
bool noConsole = false;
Expand All @@ -76,6 +85,12 @@ class domyostreadmill : public treadmill {
bool initDone = false;
bool initRequest = false;

// Async write queue management
QQueue<WriteRequest> writeQueue;
bool isWriting = false;
bool currentWriteWaitingForResponse = false;
QTimer *writeTimeoutTimer = nullptr;

#ifdef Q_OS_IOS
lockscreen *h = 0;
#endif
Expand Down
Loading
Loading