@@ -57,14 +57,20 @@ ftmsbike::ftmsbike(bool noWriteResistance, bool noHeartService, int8_t bikeResis
5757 ergModeSupported = true ; // by default ftms devices SHOULD have ergMode supported
5858 connect (refresh, &QTimer::timeout, this , &ftmsbike::update);
5959 refresh->start (settings.value (QZSettings::poll_device_time, QZSettings::default_poll_device_time).toInt ());
60+
61+ writeTimeoutTimer = new QTimer (this );
62+ writeTimeoutTimer->setSingleShot (true );
63+ connect (writeTimeoutTimer, &QTimer::timeout, this , [this ]() {
64+ qDebug () << QStringLiteral (" writeCharacteristic timeout - processing next in queue" );
65+ completeCurrentWrite ();
66+ });
67+
6068 wheelCircumference::GearTable g;
6169 g.printTable ();
6270}
6371
6472void ftmsbike::writeCharacteristicZwiftPlay (uint8_t *data, uint8_t data_len, const QString &info, bool disable_log,
6573 bool wait_for_response) {
66- QEventLoop loop;
67- QTimer timeout;
6874 QSettings settings;
6975 bool gears_zwift_ratio = settings.value (QZSettings::gears_zwift_ratio, QZSettings::default_gears_zwift_ratio).toBool ();
7076
@@ -73,37 +79,12 @@ void ftmsbike::writeCharacteristicZwiftPlay(uint8_t *data, uint8_t data_len, con
7379 return ;
7480 }
7581
76- if (wait_for_response) {
77- connect (zwiftPlayService, &QLowEnergyService::characteristicChanged, &loop, &QEventLoop::quit);
78- timeout.singleShot (300ms, &loop, &QEventLoop::quit);
79- } else {
80- connect (zwiftPlayService, &QLowEnergyService::characteristicWritten, &loop, &QEventLoop::quit);
81- timeout.singleShot (300ms, &loop, &QEventLoop::quit);
82- }
83-
84- if (writeBuffer) {
85- delete writeBuffer;
86- }
87- writeBuffer = new QByteArray ((const char *)data, data_len);
88-
89- if (zwiftPlayWriteChar.properties () & QLowEnergyCharacteristic::WriteNoResponse) {
90- zwiftPlayService->writeCharacteristic (zwiftPlayWriteChar, *writeBuffer,
91- QLowEnergyService::WriteWithoutResponse);
92- } else {
93- zwiftPlayService->writeCharacteristic (zwiftPlayWriteChar, *writeBuffer);
94- }
95-
96- if (!disable_log) {
97- emit debug (QStringLiteral (" >> " ) + writeBuffer->toHex (' ' ) + QStringLiteral (" // " ) + info);
98- }
99-
100- loop.exec ();
82+ enqueueWrite (zwiftPlayService, zwiftPlayWriteChar, data, data_len, info, disable_log, wait_for_response,
83+ zwiftPlayWriteChar.properties () & QLowEnergyCharacteristic::WriteNoResponse);
10184}
10285
10386bool ftmsbike::writeCharacteristic (uint8_t *data, uint8_t data_len, const QString &info, bool disable_log,
10487 bool wait_for_response) {
105- QEventLoop loop;
106- QTimer timeout;
10788 QSettings settings;
10889 bool gears_zwift_ratio = settings.value (QZSettings::gears_zwift_ratio, QZSettings::default_gears_zwift_ratio).toBool ();
10990
@@ -117,33 +98,74 @@ bool ftmsbike::writeCharacteristic(uint8_t *data, uint8_t data_len, const QStrin
11798 return false ;
11899 }
119100
120- if (wait_for_response) {
121- connect (gattFTMSService, &QLowEnergyService::characteristicChanged, &loop, &QEventLoop::quit);
122- timeout.singleShot (300ms, &loop, &QEventLoop::quit);
123- } else {
124- connect (gattFTMSService, &QLowEnergyService::characteristicWritten, &loop, &QEventLoop::quit);
125- timeout.singleShot (300ms, &loop, &QEventLoop::quit);
101+ return enqueueWrite (gattFTMSService, gattWriteCharControlPointId, data, data_len, info, disable_log,
102+ wait_for_response,
103+ gattWriteCharControlPointId.properties () & QLowEnergyCharacteristic::WriteNoResponse &&
104+ !DOMYOS );
105+ }
106+
107+ bool ftmsbike::enqueueWrite (QLowEnergyService *service, const QLowEnergyCharacteristic &characteristic, uint8_t *data,
108+ uint8_t data_len, const QString &info, bool disable_log, bool wait_for_response,
109+ bool write_without_response) {
110+ if (!service || !characteristic.isValid ()) {
111+ qDebug () << QStringLiteral (" writeCharacteristic error because service/characteristic is invalid" );
112+ return false ;
113+ }
114+
115+ WriteRequest request;
116+ request.data = QByteArray ((const char *)data, data_len);
117+ request.info = info;
118+ request.disable_log = disable_log;
119+ request.wait_for_response = wait_for_response;
120+ request.service = service;
121+ request.characteristic = characteristic;
122+ request.write_without_response = write_without_response;
123+
124+ writeQueue.enqueue (request);
125+ processWriteQueue ();
126+ return true ;
127+ }
128+
129+ void ftmsbike::processWriteQueue () {
130+ if (isWriting || writeQueue.isEmpty ()) {
131+ return ;
132+ }
133+
134+ WriteRequest request = writeQueue.dequeue ();
135+ if (!request.service || request.service ->state () != QLowEnergyService::ServiceDiscovered) {
136+ qDebug () << QStringLiteral (" writeCharacteristic error because the connection is closed" );
137+ writeQueue.clear ();
138+ return ;
126139 }
127140
128141 if (writeBuffer) {
129142 delete writeBuffer;
130143 }
131- writeBuffer = new QByteArray ((const char *)data, data_len);
144+ writeBuffer = new QByteArray (request.data );
145+
146+ isWriting = true ;
147+ currentWriteWaitingForResponse = request.wait_for_response ;
148+ currentWriteService = request.service ;
132149
133- if (gattWriteCharControlPointId.properties () & QLowEnergyCharacteristic::WriteNoResponse && !DOMYOS ) {
134- gattFTMSService->writeCharacteristic (gattWriteCharControlPointId, *writeBuffer,
135- QLowEnergyService::WriteWithoutResponse);
150+ if (request.write_without_response ) {
151+ request.service ->writeCharacteristic (request.characteristic , *writeBuffer, QLowEnergyService::WriteWithoutResponse);
136152 } else {
137- gattFTMSService ->writeCharacteristic (gattWriteCharControlPointId , *writeBuffer);
153+ request. service ->writeCharacteristic (request. characteristic , *writeBuffer);
138154 }
139155
140- if (!disable_log) {
141- emit debug (QStringLiteral (" >> " ) + writeBuffer->toHex (' ' ) + QStringLiteral (" // " ) + info);
156+ if (!request. disable_log ) {
157+ emit debug (QStringLiteral (" >> " ) + writeBuffer->toHex (' ' ) + QStringLiteral (" // " ) + request. info );
142158 }
143159
144- loop.exec ();
160+ writeTimeoutTimer->start (300 );
161+ }
145162
146- return true ;
163+ void ftmsbike::completeCurrentWrite () {
164+ writeTimeoutTimer->stop ();
165+ isWriting = false ;
166+ currentWriteWaitingForResponse = false ;
167+ currentWriteService = nullptr ;
168+ processWriteQueue ();
147169}
148170
149171void ftmsbike::init () {
@@ -657,6 +679,10 @@ bool ftmsbike::shouldUseCalculatedResistanceFallback(const QDateTime &now) {
657679}
658680
659681void ftmsbike::characteristicChanged (const QLowEnergyCharacteristic &characteristic, const QByteArray &newValue) {
682+ if (isWriting && currentWriteWaitingForResponse && sender () == currentWriteService) {
683+ completeCurrentWrite ();
684+ }
685+
660686 QDateTime now = QDateTime::currentDateTime ();
661687 // qDebug() << "characteristicChanged" << characteristic.uuid() << newValue << newValue.length();
662688 Q_UNUSED (characteristic);
@@ -1907,6 +1933,10 @@ void ftmsbike::descriptorRead(const QLowEnergyDescriptor &descriptor, const QByt
19071933}
19081934
19091935void ftmsbike::characteristicWritten (const QLowEnergyCharacteristic &characteristic, const QByteArray &newValue) {
1936+ if (isWriting && !currentWriteWaitingForResponse && sender () == currentWriteService) {
1937+ completeCurrentWrite ();
1938+ }
1939+
19101940 Q_UNUSED (characteristic);
19111941 emit debug (QStringLiteral (" characteristicWritten " ) + newValue.toHex (' ' ));
19121942}
0 commit comments