diff --git a/QGCPostLinkCommon.pri b/QGCPostLinkCommon.pri index 56b134823c6551939fda985e48a4edca6a0c2e54..a7c209d95a99c7bc85110adea2631cbc7e6c48f3 100644 --- a/QGCPostLinkCommon.pri +++ b/QGCPostLinkCommon.pri @@ -97,6 +97,7 @@ LinuxBuild { libQt5Sql.so.5 \ libQt5Svg.so.5 \ libQt5Test.so.5 \ + libQt5WebSockets.so.5 \ libQt5Widgets.so.5 \ libQt5X11Extras.so.5 \ libQt5XcbQpa.so.5 \ diff --git a/deploy/QGroundControl.AppImage b/deploy/QGroundControl.AppImage index b7608399415f2942aaf9d47d55bb95aab0e96f41..d61944d8650c5851b1f1b4d273055cea76c42192 100755 Binary files a/deploy/QGroundControl.AppImage and b/deploy/QGroundControl.AppImage differ diff --git a/src/MeasurementComplexItem/NemoInterface.cpp b/src/MeasurementComplexItem/NemoInterface.cpp index beed9c55f7f4550c6f7edbfb633c0f28da8c620f..f0898dda5c3e0003e81a6f3c907455fa9be005e4 100644 --- a/src/MeasurementComplexItem/NemoInterface.cpp +++ b/src/MeasurementComplexItem/NemoInterface.cpp @@ -99,7 +99,6 @@ public: const QString &warningString() const; private: - void _doTopicServiceSetup(); void _checkVersion(); void _subscribeProgressTopic(); void _subscribeHearbeatTopic(); @@ -143,8 +142,9 @@ private: void _addTilesRemote2(std::shared_ptr>> pTileArray, std::promise promise); - void _setTiles(std::shared_ptr>> pTileArray, - std::promise promise); + void + _compareAndSync(std::shared_ptr>> pTileArray, + std::promise promise); void _setVersion(QString version, std::promise promise); void _removeTilesRemote(std::shared_ptr idArray, std::promise promise); @@ -640,15 +640,11 @@ void NemoInterface::Impl::_setWarningString(const QString &warning) { } } -void NemoInterface::Impl::_doTopicServiceSetup() {} - void NemoInterface::Impl::_checkVersion() { auto pTask = std::make_unique([this] { // wait for service std::future fut; - long tries = 0; - long maxTries = 50; do { fut = this->_pRosbridge->serviceAvailable("/nemo/get_version"); @@ -662,17 +658,6 @@ void NemoInterface::Impl::_checkVersion() { break; } } - ++tries; - if (tries > maxTries) { - qCWarning(NemoInterfaceLog) - << "_checkVersion: service /nemo/get_version not available."; - bool value = - QMetaObject::invokeMethod(this->_parent /* context */, [this]() { - this->_setWarningString("Version checking failed."); - }); - Q_ASSERT(value == true); - return QVariant(false); - } } while (!fut.get()); // call service @@ -686,8 +671,6 @@ void NemoInterface::Impl::_subscribeProgressTopic() { auto pTask = std::make_unique([this] { // wait for service std::future fut; - long tries = 0; - long maxTries = 50; do { fut = this->_pRosbridge->topicAvailable(progressTopic); @@ -701,17 +684,6 @@ void NemoInterface::Impl::_subscribeProgressTopic() { break; } } - ++tries; - if (tries > maxTries) { - qCWarning(NemoInterfaceLog) - << "_subscribeProgressTopic: topic /nemo/progress not available."; - bool value = - QMetaObject::invokeMethod(this->_parent /* context */, [this]() { - this->_setWarningString("Progress topic not available."); - }); - Q_ASSERT(value == true); - return QVariant(false); - } } while (!fut.get()); // subscribe @@ -772,8 +744,6 @@ void NemoInterface::Impl::_subscribeHearbeatTopic() { auto pTask = std::make_unique([this] { // wait for service std::future fut; - long tries = 0; - long maxTries = 50; do { fut = this->_pRosbridge->topicAvailable(heartbeatTopic); @@ -787,17 +757,6 @@ void NemoInterface::Impl::_subscribeHearbeatTopic() { break; } } - ++tries; - if (tries > maxTries) { - qCWarning(NemoInterfaceLog) - << "_subscribeHeartbeatTopic: topic /nemo/hearbeat not available."; - bool value = - QMetaObject::invokeMethod(this->_parent /* context */, [this]() { - this->_setWarningString("Heartbeat topic not available."); - }); - Q_ASSERT(value == true); - return QVariant(false); - } } while (!fut.get()); // subscribe @@ -926,7 +885,7 @@ void NemoInterface::Impl::_tryRestart() { } bool NemoInterface::Impl::_isSynchronized() const { - return _localTiles.size() > 0 && _remoteTiles.size() > 0 && + return _localTiles.size() == _remoteTiles.size() && std::equal( _localTiles.begin(), _localTiles.end(), _remoteTiles.begin(), [](const auto &a, const auto &b) { return a.first == b.first; }); @@ -1416,7 +1375,7 @@ QVariant NemoInterface::Impl::_callGetAllTiles() { auto future = promise.get_future(); bool value = QMetaObject::invokeMethod( this->_parent, [this, pArray, promise = std::move(promise)]() mutable { - this->_setTiles(pArray, std::move(promise)); + this->_compareAndSync(pArray, std::move(promise)); }); Q_ASSERT(value == true); @@ -1525,17 +1484,17 @@ void NemoInterface::Impl::_addTilesRemote2( // qDebug() << "_addTilesRemote2 called"; - bool anyChange = false; bool error = false; + ProgressArray array; for (auto &&pTile : *pTileArray) { auto id = pTile->id(); auto it = _remoteTiles.find(id); if (Q_LIKELY(it == _remoteTiles.end())) { auto ret = _remoteTiles.insert(std::make_pair(id, pTile)); + array.push_back(LabeledProgress(pTile->progress(), pTile->id())); Q_ASSERT(ret.second == true); Q_UNUSED(ret); - anyChange = true; } else { qCWarning(NemoInterfaceLog) << "_addTilesRemote: tile with id " << id << " already added."; @@ -1545,40 +1504,37 @@ void NemoInterface::Impl::_addTilesRemote2( } } - if (anyChange) { + if (array.size() > 0) { if (this->_isSynchronized()) { this->_setState(STATE::READY); this->_doAction(); } + emit this->_parent->progressChanged(array); } promise.set_value(!error); } -void NemoInterface::Impl::_setTiles( +void NemoInterface::Impl::_compareAndSync( std::shared_ptr>> pTileArray, std::promise promise) { - bool error = false; - - _remoteTiles.clear(); - for (auto &&pTile : *pTileArray) { - auto id = pTile->id(); - auto it = _remoteTiles.find(id); - if (Q_LIKELY(it == _remoteTiles.end())) { - auto ret = _remoteTiles.insert(std::make_pair(id, pTile)); - Q_ASSERT(ret.second == true); - Q_UNUSED(ret); - } else { - qCWarning(NemoInterfaceLog) - << "_addTilesRemote: tile with id " << id << " already added."; - error = true; + bool synced = std::size_t(pTileArray->size()) == _localTiles.size(); + if (synced) { + for (auto it = pTileArray->begin(); it != pTileArray->end(); ++it) { + auto match = _localTiles.find((*it)->id()); + if (match == _localTiles.end()) { + synced = false; + } } } - if (error || !this->_isSynchronized()) { - qDebug() << "_setTiles: trying to synchronize"; + if (!synced) { + qDebug() << "_compareAndSync: trying to synchronize"; _trySynchronize(); + } else { + _remoteTiles.clear(); + _addTilesRemote2(pTileArray, std::promise()); } promise.set_value(true); @@ -1588,9 +1544,9 @@ void NemoInterface::Impl::_setVersion(QString version, std::promise promise) { _remoteVersion = version; if (_remoteVersion != _localVersion) { - _setWarningString("Local protocol version (" + _localVersion + - ") does not match remote version (" + _remoteVersion + - ")."); + _setWarningString("Version checking failed. Local protocol version (" + + _localVersion + ") does not match remote version (" + + _remoteVersion + ")."); } else { _versionOK = true; _doAction(); diff --git a/src/MeasurementComplexItem/nemo_interface/TaskDispatcher.cpp b/src/MeasurementComplexItem/nemo_interface/TaskDispatcher.cpp index e1b5e0820373a4d9f136ffbca220523099830561..22697a44e21a9317da3b47e6beec6bffc59de3ff 100644 --- a/src/MeasurementComplexItem/nemo_interface/TaskDispatcher.cpp +++ b/src/MeasurementComplexItem/nemo_interface/TaskDispatcher.cpp @@ -52,8 +52,8 @@ void TaskDispatcher::start() { ULock lk1(this->_mutex); if (!_running) { this->_running = true; - lk1.unlock(); _future = QtConcurrent::run([this]() mutable { return this->run(); }); + lk1.unlock(); } } @@ -67,8 +67,8 @@ void TaskDispatcher::stop() { } void TaskDispatcher::reset() { - clear(); stop(); + clear(); } bool TaskDispatcher::isInterruptionRequested() { @@ -102,7 +102,10 @@ void TaskDispatcher::run() { lk1.unlock(); // exec task - promise.set_value(pTask->exec()); + QVariant var = pTask->exec(); + bool r = var.toBool(); + Q_ASSERT(r == true || r == false); + promise.set_value(var); } else { this->_running = false; lk1.unlock(); diff --git a/src/MeasurementComplexItem/qml/NemoEditor.qml b/src/MeasurementComplexItem/qml/NemoEditor.qml index 0629c98b263d99bd7e9a8952c600423de29dc04c..8e42193416aef76b5d17a3f299c90eb3fefdc345 100644 --- a/src/MeasurementComplexItem/qml/NemoEditor.qml +++ b/src/MeasurementComplexItem/qml/NemoEditor.qml @@ -20,7 +20,6 @@ Rectangle { property bool checked: true property var missionItem: undefined property int availableWidth: 300 - property bool error: errorString.lenght >= 0 readonly property bool running: _nemoInterface.running property string warningString: _nemoInterface.warningString property string infoString: _nemoInterface.infoString @@ -44,21 +43,6 @@ Rectangle { rowSpacing: _margin columns: 2 - QGCLabel { - text: _root.errorString - wrapMode: Text.WordWrap - horizontalAlignment: Text.AlignLeft - color: "orange" - Layout.columnSpan: parent.columns - Layout.fillWidth: true - } - QGCLabel { - text: _root.infoString - wrapMode: Text.WordWrap - horizontalAlignment: Text.AlignLeft - Layout.columnSpan: parent.columns - Layout.fillWidth: true - } QGCButton { text: running ? qsTr("Stop") : qsTr("Start") @@ -81,6 +65,24 @@ Rectangle { Layout.fillWidth: true } + QGCLabel { + text: _root.warningString + visible: text.length > 0 + wrapMode: Text.WordWrap + horizontalAlignment: Text.AlignLeft + color: "orange" + Layout.columnSpan: parent.columns + Layout.fillWidth: true + } + QGCLabel { + text: _root.infoString + visible: text.length > 0 + wrapMode: Text.WordWrap + horizontalAlignment: Text.AlignLeft + Layout.columnSpan: parent.columns + Layout.fillWidth: true + } + SectionHeader { id: progressHeader Layout.fillWidth: true diff --git a/src/MeasurementComplexItem/rosbridge/rosbridgeimpl.cpp b/src/MeasurementComplexItem/rosbridge/rosbridgeimpl.cpp index 5b1ca5cb3a53a3b58e0fafd0b88d03560b9bf0d3..4a21f54548c720f901eb5b5d412b8e8e43b1c653 100644 --- a/src/MeasurementComplexItem/rosbridge/rosbridgeimpl.cpp +++ b/src/MeasurementComplexItem/rosbridge/rosbridgeimpl.cpp @@ -3,6 +3,7 @@ #include #include #include +#include static const char *advertiseOpKey = "advertise"; static const char *subscribeOpKey = "subscribe"; @@ -259,6 +260,8 @@ void RosbridgeImpl::_clearAllPendingServiceCalls() { } } +void RosbridgeImpl::_checkIfConnected() {} + void RosbridgeImpl::callService(const QString &service, const Rosbridge::CallBack &callback, const QJsonObject &req) { @@ -368,6 +371,14 @@ void RosbridgeImpl::_doAction() { break; case STATE::STARTING: _webSocket.open(_url); + + // open again if no connection was established + QTimer::singleShot(2000, this, [this] { + if (this->_state == STATE::STARTING) { + _doAction(); + } + }); + break; case STATE::TIMEOUT: break; diff --git a/src/MeasurementComplexItem/rosbridge/rosbridgeimpl.h b/src/MeasurementComplexItem/rosbridge/rosbridgeimpl.h index 605550c9b4772fdee654a676cf4b642f678593e5..d2ea0c2689f650620e5ae002b969fced85f0a885 100644 --- a/src/MeasurementComplexItem/rosbridge/rosbridgeimpl.h +++ b/src/MeasurementComplexItem/rosbridge/rosbridgeimpl.h @@ -71,6 +71,7 @@ private: void _serviceResponse(const QString &service, const QString &id, bool result, const QJsonObject &values); void _clearAllPendingServiceCalls(); + void _checkIfConnected(); QWebSocket _webSocket; QUrl _url;