Newer
Older
#include "NemoInterface.h"
#include "QGCApplication.h"
#include "QGCLoggingCategory.h"
#include "QGCToolbox.h"
#include "SettingsFact.h"
#include "SettingsManager.h"
#include "WimaSettings.h"
#include <shared_mutex>
#include <QJsonArray>
#include <QJsonObject>
#include "GenericSingelton.h"
#include "geometry/MeasurementArea.h"
Valentin Platzgummer
committed
#include "geometry/geometry.h"
#include "nemo_interface/MeasurementTile.h"
#include "nemo_interface/QNemoHeartbeat.h"
#include "ros_bridge/include/messages/geographic_msgs/geopoint.h"
#include "ros_bridge/include/messages/nemo_msgs/heartbeat.h"
#include "ros_bridge/include/messages/nemo_msgs/progress_array.h"
#include "rosbridge/rosbridge.h"
QGC_LOGGING_CATEGORY(NemoInterfaceLog, "NemoInterfaceLog")
#define SYNC_INTERVAL 1000 // ms
#define NO_HEARTBEAT_TIMEOUT 5000 // ms
static constexpr auto maxResponseTime = std::chrono::milliseconds(10000);
static const char *progressTopic = "/nemo/progress";
static const char *heartbeatTopic = "/nemo/heartbeat";
using ROSBridgePtr = std::shared_ptr<Rosbridge>;
typedef ros_bridge::messages::nemo_msgs::tile::GenericTile<QGeoCoordinate,
QList>
Tile;
typedef std::map<QString, std::shared_ptr<Tile>> TileMap;
typedef std::map<QString, std::shared_ptr<const Tile>> TileMapConst;
typedef ros_bridge::messages::nemo_msgs::heartbeat::Heartbeat Heartbeat;
typedef nemo_interface::TaskDispatcher Dispatcher;
typedef nemo_interface::FutureWatcher<QVariant, std::shared_future>
FutureWatcher;
// Tile editing.
// Functions that require communication to device.
std::shared_future<QVariant> addTiles(const TilePtrArray &tileArray);
std::shared_future<QVariant> removeTiles(const IDArray &idArray);
std::shared_future<QVariant> clearTiles();
TileArray getTiles(const IDArray &idArray) const;
TileArray getAllTiles() const;
LogicalArray containsTiles(const IDArray &idArray) const;
std::size_t size() const;
bool empty() const;
ProgressArray getProgress() const;
ProgressArray getProgress(const IDArray &idArray) const;
NemoInterface::STATUS status() const;
bool running() const; // thread safe
bool ready() const; // thread safe
const QString &infoString() const;
const QString &warningString() const;
bool _isSynchronized() const;
bool _userSync() const; // thread safe
bool _sysSync() const; // thread safe
void _onHeartbeatTimeout(); // thread safe
void _onRosbridgeStateChanged();
// called from dispatcher thread!
QVariant _callAddTiles(
std::shared_ptr<QVector<std::shared_ptr<const Tile>>> pTileArray);
// called from dispatcher thread!
QVariant _callRemoveTiles(std::shared_ptr<IDArray> pIdArray);
// called from dispatcher thread!
QVariant _callClearTiles();
// called from dispatcher thread!
QVariant _callGetProgress(std::shared_ptr<IDArray> pIdArray);
QVariant _callGetAllProgress();
enum class CALL_NAME {
ADD_TILES,
REMOVE_TILES,
CLEAR_TILES,
GET_PROGRESS,
GET_ALL_PROGRESS
};
std::shared_ptr<QVector<std::shared_ptr<const Tile>>> pTileArray,
std::promise<bool> promise);
_addTilesRemote2(std::shared_ptr<QVector<std::shared_ptr<Tile>>> pTileArray,
std::promise<bool> promise);
void _removeTilesRemote(std::shared_ptr<IDArray> idArray,
std::promise<bool> promise);
void _clearTilesRemote(std::promise<bool> promise);
void _updateProgress(std::shared_ptr<ProgressArray> pArray,
std::promise<bool> promise);
void _onHeartbeatReceived(const QNemoHeartbeat &hb,
std::promise<bool> promise);
void _setInfoString(const QString &info);
void _setWarningString(const QString &warning);
static bool _userSync(STATE s);
static bool _sysSync(STATE s);
static NemoInterface::STATUS _status(STATE state);
static QString _toString(STATE s);
static QString _toString(NemoInterface::STATUS s);
TileMap _remoteTiles;
TileMapConst _localTiles;
NemoInterface *const _parent;
Dispatcher _dispatcher;
QString _infoString;
QString _warningString;
QTimer _timeoutTimer;
QNemoHeartbeat _lastHeartbeat;
};
using StatusMap = std::map<NemoInterface::STATUS, QString>;
static StatusMap statusMap{
std::make_pair<NemoInterface::STATUS, QString>(
NemoInterface::STATUS::NOT_CONNECTED, "Not Connected"),
std::make_pair<NemoInterface::STATUS, QString>(NemoInterface::STATUS::SYNC,
"Synchronizing"),
std::make_pair<NemoInterface::STATUS, QString>(NemoInterface::STATUS::READY,
"Ready"),
std::make_pair<NemoInterface::STATUS, QString>(
NemoInterface::STATUS::TIMEOUT, "Timeout"),
std::make_pair<NemoInterface::STATUS, QString>(
NemoInterface::STATUS::WEBSOCKET_DETECTED, "Websocket Detected")};
NemoInterface::Impl::Impl(NemoInterface *p)
// ROS Bridge.
WimaSettings *wimaSettings =
qgcApp()->toolbox()->settingsManager()->wimaSettings();
auto connectionStringFact = wimaSettings->rosbridgeConnectionString();
auto setConnectionString = [connectionStringFact, this] {
auto connectionString = connectionStringFact->rawValue().toString();
this->_pRosbridge = std::make_shared<Rosbridge>(
QUrl(QString("ws://") + connectionString.toLocal8Bit().data()));
};
connect(connectionStringFact, &SettingsFact::rawValueChanged,
setConnectionString);
setConnectionString();
connect(&this->_timeoutTimer, &QTimer::timeout,
std::bind(&Impl::_onHeartbeatTimeout, this));
connect(this->_pRosbridge.get(), &Rosbridge::stateChanged,
[this] { this->_onRosbridgeStateChanged(); });
connect(&this->_futureWatcher, &FutureWatcher::finished,
[this] { this->_onFutureWatcherFinished(); });
NemoInterface::Impl::~Impl() { this->_pRosbridge->stop(); }
if (!running()) {
this->_setState(STATE::START_BRIDGE);
this->_doAction();
}
if (running()) {
this->_setState(STATE::STOPPED);
this->_doAction();
}
std::shared_future<QVariant>
NemoInterface::Impl::addTiles(const TilePtrArray &tileArray) {
// qDebug() << "addTiles called";
if (tileArray.size() > 0) {
// copy unknown tiles
auto pTileArray = std::make_shared<QVector<std::shared_ptr<const Tile>>>();
for (const auto *pTile : tileArray) {
auto id = pTile->id();
const auto it = this->_localTiles.find(id);
Q_ASSERT(it == _localTiles.end());
if (Q_LIKELY(it == _localTiles.end())) {
auto pTileCopy =
std::make_shared<const Tile>(pTile->coordinateList(), 0.0, id);
_localTiles.insert(std::make_pair(id, pTileCopy));
pTileArray->push_back(pTileCopy);
} else {
qCDebug(NemoInterfaceLog)
<< "addTiles(): tile with id: " << pTile->id() << "already added.";
}
}
if (pTileArray->size() > 0) {
this->_parent->tilesChanged();
}
// ready for send?
if (pTileArray->size() > 0 && (this->ready() || this->_userSync())) {
// create add tiles command.
auto pTask = std::make_unique<Task>(
// dispatch command.
auto ret = _dispatcher.dispatch(std::move(pTask));
auto addFuture = ret.share();
// create get progress cmd.
pTask = std::make_unique<Task>([this, addFuture, pIdArray] {
addFuture.wait();
if (addFuture.get().toBool()) {
return this->_callGetProgress(pIdArray);
} else {
return QVariant(false);
}
});
// dispatch command.
ret = _dispatcher.dispatch(std::move(pTask));
auto progressFuture = ret.share();
_futureWatcher.setFuture(progressFuture);
return progressFuture;
}
}
std::promise<QVariant> p;
p.set_value(QVariant(false));
return p.get_future();
}
std::shared_future<QVariant>
NemoInterface::Impl::removeTiles(const IDArray &idArray) {
using namespace nemo_interface;
// qDebug() << "removeTiles called";
if (idArray.size() > 0) {
// copy known ids
auto pIdArray = std::make_shared<IDArray>();
for (const auto id : idArray) {
const auto it = this->_localTiles.find(id);
Q_ASSERT(it != _localTiles.end());
if (Q_LIKELY(it != _localTiles.end())) {
_localTiles.erase(it);
pIdArray->push_back(id);
} else {
qCDebug(NemoInterfaceLog) << "removeTiles(): unknown id: " << id << ".";
if (pIdArray->size() > 0) {
this->_parent->tilesChanged();
}
// ready for send?
if (pIdArray->size() > 0 && (this->ready() || this->_userSync())) {
this->_doAction();
// create command.
auto cmd = std::make_unique<Task>(
std::bind(&Impl::_callRemoveTiles, this, pIdArray));
// dispatch command and return.
auto ret = _dispatcher.dispatch(std::move(cmd));
auto sfut = ret.share();
_futureWatcher.setFuture(sfut);
return sfut;
}
}
std::promise<QVariant> p;
p.set_value(QVariant(false));
return p.get_future();
}
std::shared_future<QVariant> NemoInterface::Impl::clearTiles() {
using namespace nemo_interface;
// qDebug() << "clearTiles called";
if (!_localTiles.empty()) {
this->_localTiles.clear();
this->_parent->tilesChanged();
}
// create command.
auto pTask =
std::make_unique<Task>(std::bind(&Impl::_callClearTiles, this));
auto ret = _dispatcher.dispatch(std::move(pTask));
auto sfut = ret.share();
_futureWatcher.setFuture(sfut);
return sfut;
} else {
std::promise<QVariant> p;
p.set_value(QVariant(false));
return p.get_future();
}
}
TileArray NemoInterface::Impl::getTiles(const IDArray &idArray) const {
if (this->ready()) {
for (const auto &id : idArray) {
const auto it = _remoteTiles.find(id);
if (it != _remoteTiles.end()) {
MeasurementTile copy;
copy.setId(it->second->id());
copy.setProgress(it->second->progress());
copy.setPath(it->second->tile());
tileArray.append(std::move(copy));
}
}
} else {
for (const auto &id : idArray) {
const auto it = _localTiles.find(id);
if (it != _localTiles.end()) {
MeasurementTile copy;
copy.setId(it->second->id());
copy.setProgress(it->second->progress());
copy.setPath(it->second->tile());
tileArray.append(std::move(copy));
}
TileArray NemoInterface::Impl::getAllTiles() const {
if (this->ready()) {
for (const auto &entry : _remoteTiles) {
auto pTile = entry.second;
MeasurementTile copy;
copy.setId(pTile->id());
copy.setProgress(pTile->progress());
copy.setPath(pTile->tile());
tileArray.append(std::move(copy));
}
} else {
for (const auto &entry : _localTiles) {
auto pTile = entry.second;
MeasurementTile copy;
copy.setId(pTile->id());
copy.setProgress(pTile->progress());
copy.setPath(pTile->tile());
tileArray.append(std::move(copy));
}
LogicalArray NemoInterface::Impl::containsTiles(const IDArray &idArray) const {
LogicalArray logicalArray;
for (const auto &id : idArray) {
const auto &it = _localTiles.find(id);
logicalArray.append(it != _localTiles.end());
std::size_t NemoInterface::Impl::size() const { return _localTiles.size(); }
bool NemoInterface::Impl::empty() const { return _localTiles.empty(); }
ProgressArray NemoInterface::Impl::getProgress() const {
if (this->_isSynchronized()) {
for (const auto &entry : _remoteTiles) {
progressArray.append(
LabeledProgress{entry.second->progress(), entry.second->id()});
}
} else {
for (const auto &entry : _localTiles) {
progressArray.append(
LabeledProgress{entry.second->progress(), entry.second->id()});
}
ProgressArray NemoInterface::Impl::getProgress(const IDArray &idArray) const {
if (this->_isSynchronized()) {
for (const auto &id : idArray) {
const auto it = _remoteTiles.find(id);
if (it != _remoteTiles.end()) {
progressArray.append(
LabeledProgress{it->second->progress(), it->second->id()});
}
}
} else {
for (const auto &id : idArray) {
const auto it = _localTiles.find(id);
if (it != _localTiles.end()) {
progressArray.append(
LabeledProgress{it->second->progress(), it->second->id()});
}
NemoInterface::STATUS NemoInterface::Impl::status() const {
bool NemoInterface::Impl::running() const { return _running(this->_state); }
bool NemoInterface::Impl::ready() const { return _ready(this->_state.load()); }
bool NemoInterface::Impl::_sysSync() const { return _sysSync(this->_state); }
if (this->ready() || this->_userSync() || this->_sysSync()) {
auto lastTransactionSuccessfull = _futureWatcher.result().toBool();
if (!lastTransactionSuccessfull) {
qCDebug(NemoInterfaceLog)
<< "last transaction unsuccessfull: " << _toString(_lastCall);
QTimer::singleShot(5000, [this] { this->_trySynchronize(); });
void NemoInterface::Impl::_onHeartbeatTimeout() {
this->_setState(STATE::HEARTBEAT_TIMEOUT);
this->_doAction();
}
void NemoInterface::Impl::_onRosbridgeStateChanged() {
auto state = this->_pRosbridge->state();
if (state == Rosbridge::STATE::CONNECTED) {
if (this->_state == STATE::START_BRIDGE ||
this->_state == STATE::WEBSOCKET_TIMEOUT) {
this->_setState(STATE::WEBSOCKET_DETECTED);
this->_doAction();
}
} else if (state == Rosbridge::STATE::TIMEOUT) {
if (this->_state == STATE::TRY_TOPIC_SERVICE_SETUP ||
this->_state == STATE::READY ||
this->_state == STATE::WEBSOCKET_DETECTED ||
this->_state == STATE::HEARTBEAT_TIMEOUT) {
this->_setState(STATE::WEBSOCKET_TIMEOUT);
this->_doAction();
}
}
}
bool NemoInterface::Impl::_userSync() const { return _userSync(this->_state); }
const QString &NemoInterface::Impl::infoString() const { return _infoString; }
const QString &NemoInterface::Impl::warningString() const {
return _warningString;
}
void NemoInterface::Impl::_updateProgress(std::shared_ptr<ProgressArray> pArray,
std::promise<bool> promise) {
// qDebug() << "_updateProgress called";
if (Q_LIKELY(it != _remoteTiles.end())) {
it->second->setProgress(itLP->progress());
++itLP;
<< "_updateProgress(): tile with id " << itLP->id() << " not found.";
itLP = pArray->erase(itLP);
if (pArray->size() > 0) {
emit _parent->progressChanged(*pArray);
}
void NemoInterface::Impl::_onHeartbeatReceived(const QNemoHeartbeat &hb,
std::promise<bool> promise) {
_lastHeartbeat = hb;
this->_timeoutTimer.start(NO_HEARTBEAT_TIMEOUT);
if (this->_state == STATE::TRY_TOPIC_SERVICE_SETUP) {
this->_setState(STATE::READY);
this->_doAction();
} else if (this->_state == STATE::HEARTBEAT_TIMEOUT) {
this->_setState(STATE::READY);
this->_doAction();
}
void NemoInterface::Impl::_setInfoString(const QString &info) {
if (_infoString != info) {
_infoString = info;
emit this->_parent->infoStringChanged();
}
}
void NemoInterface::Impl::_setWarningString(const QString &warning) {
if (_warningString != warning) {
_warningString = warning;
emit this->_parent->warningStringChanged();
}
}
void NemoInterface::Impl::_doTopicServiceSetup() {
this->_pRosbridge->subscribeTopic(
progressTopic, [this](const QJsonObject &o) {
nemo_msgs::progress_array::ProgressArray progressArray;
if (nemo_msgs::progress_array::fromJson(o, progressArray)) {
// correct range errors of progress
for (auto &lp : progressArray.progress_array()) {
bool rangeError = false;
if (lp.progress() < 0) {
lp.setProgress(0);
rangeError = true;
}
if (lp.progress() > 100) {
lp.setProgress(100);
rangeError = true;
}
if (rangeError) {
qCWarning(NemoInterfaceLog) << "/nemo/progress progress out "
"of range, value was set to: "
<< lp.progress();
auto p = std::make_shared<ProgressArray>();
*p = std::move(progressArray.progress_array());
std::promise<bool> promise;
auto future = promise.get_future();
bool value = QMetaObject::invokeMethod(
this->_parent, [this, p, promise = std::move(promise)]() mutable {
this->_updateProgress(p, std::move(promise));
});
Q_ASSERT(value == true);
future.wait();
qCWarning(NemoInterfaceLog) << "/nemo/progress not able to "
"create ProgressArray form json: "
this->_pRosbridge->subscribeTopic(
heartbeatTopic, [this](const QJsonObject &o) {
nemo_msgs::heartbeat::Heartbeat heartbeat;
if (nemo_msgs::heartbeat::fromJson(o, heartbeat)) {
std::promise<bool> promise;
auto future = promise.get_future();
bool value = QMetaObject::invokeMethod(
this->_parent,
[this, heartbeat, promise = std::move(promise)]() mutable {
this->_onHeartbeatReceived(heartbeat, std::move(promise));
});
Q_ASSERT(value == true);
future.wait();
qCWarning(NemoInterfaceLog) << "/nemo/heartbeat not able to "
"create Heartbeat form json: "
if ((this->_state == STATE::READY || this->_state == STATE::SYS_SYNC ||
this->_state == STATE::USER_SYNC) &&
!_isSynchronized()) {
if (!_dispatcher.idle()) {
QTimer::singleShot(5000, [this] { this->_trySynchronize(); });
return;
}
qCWarning(NemoInterfaceLog) << "trying to synchronize";
this->_doAction();
// create clear cmd.
auto pTask = std::make_unique<nemo_interface::Task>(
std::bind(&Impl::_callClearTiles, this));
// dispatch command.
Q_ASSERT(_dispatcher.pendingTasks() == 0);
auto ret = _dispatcher.dispatch(std::move(pTask));
// create tile array.
auto pTileArray = std::make_shared<QVector<std::shared_ptr<const Tile>>>();
for (auto pair : _localTiles) {
pTileArray->push_back(pair.second);
}
// create addTiles cmd.
pTask =
std::make_unique<nemo_interface::Task>([this, pTileArray, clearFuture] {
clearFuture.wait();
if (clearFuture.get().toBool()) {
return this->_callAddTiles(pTileArray);
} else {
return QVariant(false);
}
});
// dispatch command.
ret = _dispatcher.dispatch(std::move(pTask));
auto addFuture = ret.share();
// create GetAllProgress cmd.
pTask = std::make_unique<nemo_interface::Task>([this, addFuture] {
addFuture.wait();
if (addFuture.get().toBool()) {
return this->_callGetAllProgress();
} else {
return QVariant(false);
}
});
bool NemoInterface::Impl::_isSynchronized() const {
return _localTiles.size() > 0 && _remoteTiles.size() > 0 &&
std::equal(
_localTiles.begin(), _localTiles.end(), _remoteTiles.begin(),
[](const auto &a, const auto &b) { return a.first == b.first; });
}
this->_clearTilesRemote(std::promise<bool>());
if (this->_pRosbridge->state() != Rosbridge::STATE::STOPPED) {
this->_pRosbridge->stop();
this->_setState(STATE::TRY_TOPIC_SERVICE_SETUP);
this->_doAction();
break;
case STATE::TRY_TOPIC_SERVICE_SETUP:
this->_doTopicServiceSetup();
this->_clearTilesRemote(std::promise<bool>());
break;
case STATE::WEBSOCKET_TIMEOUT:
if (!resetDone) {
resetDone = true;
this->_pRosbridge->stop();
this->_pRosbridge->start();
this->_timeoutTimer.stop();
this->_clearTilesRemote(std::promise<bool>());
QVariant NemoInterface::Impl::_callAddTiles(
std::shared_ptr<QVector<std::shared_ptr<const Tile>>> pTileArray) {
// qDebug() << "_callAddTiles called";
QJsonArray jsonTileArray;
for (const auto &tile : *pTileArray) {
using namespace ros_bridge::messages;
QJsonObject jsonTile;
if (!nemo_msgs::tile::toJson(*tile, jsonTile)) {
qCDebug(NemoInterfaceLog)
<< "addTiles(): not able to create json object: tile id: "
<< tile->id() << " progress: " << tile->progress()
<< " points: " << tile->tile();
}
jsonTileArray.append(std::move(jsonTile));
QJsonObject req;
req["in_tile_array"] = std::move(jsonTileArray);
// create response handler.
auto promise_response = std::make_shared<std::promise<bool>>();
auto future_response = promise_response->get_future();
auto responseHandler = [promise_response](const QJsonObject &o) mutable {
// check if transaction was successfull
if (o.contains("success") && o["success"].isBool()) {
promise_response->set_value(o["success"].toBool());
qCWarning(NemoInterfaceLog)
<< "/nemo/add_tiles no \"success\" key or wrong type: " << o;
promise_response->set_value(false);
}
};
this->_pRosbridge->callService("/nemo/add_tiles", responseHandler, req);
// wait for response.
auto tStart = hrc::now();
bool abort = true;
do {
auto status = future_response.wait_for(std::chrono::milliseconds(100));
if (status == std::future_status::ready) {
abort = false;
break;
}
} while (hrc::now() - tStart < maxResponseTime ||
this->_dispatcher.isInterruptionRequested());
if (abort) {
qCWarning(NemoInterfaceLog)
<< "addTiles(): Websocket not responding to request.";
return QVariant(false);
}
// transaction error?
if (!future_response.get()) {
return QVariant(false);
}
// add remote tiles (_remoteTiles)
std::promise<bool> promise;
auto future = promise.get_future();
bool value = QMetaObject::invokeMethod(
this->_parent /* context */,
[this, pTileArray, promise = std::move(promise)]() mutable {
this->_addTilesRemote(pTileArray, std::move(promise));
});
Q_ASSERT(value == true);
}
QVariant
NemoInterface::Impl::_callRemoveTiles(std::shared_ptr<IDArray> pIdArray) {
// qDebug() << "_callRemoveTiles called";
QJsonArray jsonIdArray;
for (const auto id : *pIdArray) {
using namespace ros_bridge::messages;
jsonIdArray.append(id);
QJsonObject req;
req["ids"] = std::move(jsonIdArray);
// create response handler.
auto promise_response = std::make_shared<std::promise<bool>>();
auto future_response = promise_response->get_future();
auto responseHandler = [promise_response](const QJsonObject &o) mutable {
// check if transaction was successfull
QString msg = QJsonDocument(o).toJson(QJsonDocument::JsonFormat::Compact);
if (o.contains("success") && o["success"].isBool()) {
promise_response->set_value(o["success"].toBool());
qCWarning(NemoInterfaceLog)
<< "/nemo/remove_tiles no \"success\" key or wrong type: " << msg;
promise_response->set_value(false);
}
};
this->_pRosbridge->callService("/nemo/remove_tiles", responseHandler, req);
// wait for response.
auto tStart = hrc::now();
bool abort = true;
do {
auto status = future_response.wait_for(std::chrono::milliseconds(100));
if (status == std::future_status::ready) {
abort = false;
break;
}
} while (hrc::now() - tStart < maxResponseTime ||
this->_dispatcher.isInterruptionRequested());
if (abort) {
qCWarning(NemoInterfaceLog)
<< "remove_tiles(): Websocket not responding to request.";
return QVariant(false);
}
// transaction error?
if (!future_response.get()) {
return QVariant(false);
}
// remove remote tiles (_remoteTiles)
std::promise<bool> promise;
auto future = promise.get_future();
bool value = QMetaObject::invokeMethod(
this->_parent /* context */,
[this, pIdArray, promise = std::move(promise)]() mutable {
this->_removeTilesRemote(pIdArray, std::move(promise));
});
Q_ASSERT(value == true);
// qDebug() << "_callClearTiles called";
// create response handler.
auto promise_response = std::make_shared<std::promise<bool>>();
auto future_response = promise_response->get_future();
auto responseHandler = [promise_response](const QJsonObject &o) mutable {
// check if transaction was successfull
promise_response->set_value(true);
this->_pRosbridge->callService("/nemo/clear_tiles", responseHandler,
QJsonObject());
// wait for response.
auto tStart = hrc::now();
bool abort = true;
do {
auto status = future_response.wait_for(std::chrono::milliseconds(100));
if (status == std::future_status::ready) {
abort = false;
break;
}
} while (hrc::now() - tStart < maxResponseTime ||
this->_dispatcher.isInterruptionRequested());
if (abort) {
qCWarning(NemoInterfaceLog) << "Websocket not responding to request.";
return QVariant(false);
}
// transaction failed?
if (!future_response.get()) {
return QVariant(false);
}
// clear remote tiles (_remoteTiles)
std::promise<bool> promise;
auto future = promise.get_future();
bool value = QMetaObject::invokeMethod(
this->_parent, [this, promise = std::move(promise)]() mutable {
this->_clearTilesRemote(std::move(promise));
});
Q_ASSERT(value == true);
}
QVariant
NemoInterface::Impl::_callGetProgress(std::shared_ptr<IDArray> pIdArray) {
// qDebug() << "_callGetProgress called";
QJsonArray jsonIdArray;
for (const auto id : *pIdArray) {
using namespace ros_bridge::messages;
jsonIdArray.append(id);
QJsonObject req;
req["ids"] = std::move(jsonIdArray);
// create response handler.
typedef std::shared_ptr<ProgressArray> ResponseType;
auto promise_response = std::make_shared<std::promise<ResponseType>>();
auto future_response = promise_response->get_future();
auto responseHandler = [promise_response](const QJsonObject &o) mutable {
// check if transaction was successfull
ros_bridge::messages::nemo_msgs::progress_array::ProgressArray
progressArrayMsg;
if (ros_bridge::messages::nemo_msgs::progress_array::fromJson(
o, progressArrayMsg)) {