Commit 7308bf55 authored by Valentin Platzgummer's avatar Valentin Platzgummer

nemo interface improved

parent 29514d84
......@@ -463,7 +463,6 @@ HEADERS += \
src/MeasurementComplexItem/nemo_interface/Task.h \
src/MeasurementComplexItem/nemo_interface/TaskDispatcher.h \
src/MeasurementComplexItem/nemo_interface/tileHelper.h \
src/MeasurementComplexItem/routing.h \
src/comm/ros_bridge/include/messages/nemo_msgs/labeled_progress.h \
src/MeasurementComplexItem/nemo_interface/MeasurementTile.h \
src/QmlControls/QmlUnitsConversion.h \
......@@ -539,7 +538,6 @@ SOURCES += \
src/MeasurementComplexItem/nemo_interface/MeasurementTile.cpp \
src/MeasurementComplexItem/nemo_interface/Task.cpp \
src/MeasurementComplexItem/nemo_interface/TaskDispatcher.cpp \
src/MeasurementComplexItem/routing.cpp \
src/Vehicle/VehicleEscStatusFactGroup.cc \
src/MeasurementComplexItem/AreaData.cc \
src/api/QGCCorePlugin.cc \
......
......@@ -7,7 +7,7 @@
#include "SettingsManager.h"
#include "WimaSettings.h"
#include <shared_mutex>
#include <mutex>
#include <QJsonArray>
#include <QJsonObject>
......@@ -17,7 +17,6 @@
#include "GenericSingelton.h"
#include "geometry/MeasurementArea.h"
#include "geometry/geometry.h"
#include "nemo_interface/FutureWatcher.h"
#include "nemo_interface/MeasurementTile.h"
#include "nemo_interface/QNemoHeartbeat.h"
#include "nemo_interface/TaskDispatcher.h"
......@@ -29,6 +28,30 @@
#include "ros_bridge/include/messages/nemo_msgs/tile_array.h"
#include "rosbridge/rosbridge.h"
/*
* Here some rules:
* * not threas safe functions are marked with *NotSafe(...)
* * If a function is not safe:
* * the call to it must be protected with a Lock.
* * not safe functions are not allowed to emit signals directly (danger of
* deadlock).
* * if a not safe function needs to emit a signal, defere it with
* QTimer::singleShot().
* * not safe functions are allowed to call other not safe functions
* * it is a bad idea to wait inside a not safe function for a asynchronous
* operation (potential deadlock)
* * Functions that are not marked with *NotSafe(...) must be thread safe!
*/
#define INVM(context, fun) \
{ \
auto value = QMetaObject::invokeMethod(context, fun); \
Q_ASSERT(value == true); \
Q_UNUSED(value); \
}
Q_DECLARE_METATYPE(ProgressArray)
QGC_LOGGING_CATEGORY(NemoInterfaceLog, "NemoInterfaceLog")
#define NO_HEARTBEAT_TIMEOUT 5000 // ms
......@@ -36,10 +59,32 @@ QGC_LOGGING_CATEGORY(NemoInterfaceLog, "NemoInterfaceLog")
#define RESTART_RETRY_INTERVAl 2000 // ms
#define SYNC_INTERVAL 10000 // ms
#define SYNC_RETRY_INTERVAL 2000 // ms
static constexpr auto maxResponseTime = std::chrono::milliseconds(10000);
static const char *progressTopic = "/nemo/progress";
static const char *heartbeatTopic = "/nemo/heartbeat";
static char const *progressTopic = "/nemo/progress";
static char const *heartbeatTopic = "/nemo/heartbeat";
static char const *addTilesService = "/nemo/add_tiles";
static char const *removeTilesService = "/nemo/remove_tiles";
static char const *clearTilesService = "/nemo/clear_tiles";
static char const *getAllTilesService = "/nemo/get_all_tiles";
// static char const *getTilesService = "/nemo/get_tiles";
// static char const *containsTilesService = "/nemo/contains_tiles";
// static char const *extractTilesService = "/nemo/extract_tiles";
// static char const *sizeService = "/nemo/size";
// static char const *emptyService = "/nemo/empty";
static char const *getProgressService = "/nemo/get_progress";
static char const *getAllProgressService = "/nemo/get_all_progress";
static char const *getVersionService = "/nemo/get_version";
static const std::vector<char const *> requiredServices{
addTilesService, removeTilesService, clearTilesService,
getAllTilesService, getAllProgressService, getProgressService,
getVersionService};
static const std::vector<char const *> requiredTopics{progressTopic,
heartbeatTopic};
using hrc = std::chrono::high_resolution_clock;
using ROSBridgePtr = std::shared_ptr<Rosbridge>;
......@@ -51,8 +96,7 @@ 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;
typedef std::unique_lock<std::mutex> Lock;
class NemoInterface::Impl {
enum class STATE {
......@@ -62,6 +106,7 @@ class NemoInterface::Impl {
TRY_SETUP,
USER_SYNC,
SYS_SYNC,
SYNC_ERROR,
READY,
WEBSOCKET_TIMEOUT,
HEARTBEAT_TIMEOUT
......@@ -99,96 +144,84 @@ public:
const QString &warningString() const;
private:
void _checkVersion();
void _subscribeProgressTopic();
void _subscribeHearbeatTopic();
void _doAction();
void _trySynchronize();
void _synchronizeIfNeccessary();
void _doSetup();
void _doActionNotSafe();
void _synchronize();
void _tryRestart();
bool _isSynchronizedNotSafe() const;
bool _isSynchronized() const;
bool _userSync() const; // thread safe
bool _sysSync() const; // thread safe
void _onFutureWatcherFinished(); // thread safe
void _onHeartbeatTimeout(); // thread safe
void _onHeartbeatTimeout();
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();
QVariant _callGetAllTiles();
QVariant _callGetVersion();
enum class CALL_NAME {
ADD_TILES,
REMOVE_TILES,
CLEAR_TILES,
GET_PROGRESS,
GET_ALL_TILES,
GET_ALL_PROGRESS,
GET_VERSION
};
QString _toString(CALL_NAME name);
void _addTilesRemote(
std::shared_ptr<QVector<std::shared_ptr<const Tile>>> pTileArray,
std::promise<bool> promise);
void
_addTilesRemote2(std::shared_ptr<QVector<std::shared_ptr<Tile>>> pTileArray,
std::promise<bool> promise);
void
_compareAndSync(std::shared_ptr<QVector<std::shared_ptr<Tile>>> pTileArray,
std::promise<bool> promise);
void _setVersion(QString version, 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);
bool _updateProgress(const ProgressArray &pArray);
void _onHeartbeatReceived(const QNemoHeartbeat &hb);
void _setInfoStringNotSafe(const QString &info);
void _setWarningStringNotSafe(const QString &warning);
void _setInfoString(const QString &info);
void _setWarningString(const QString &warning);
bool _setState(STATE newState); // not thread safe
static bool _ready(STATE s);
static bool _userSync(STATE s);
static bool _sysSync(STATE s);
static bool _running(STATE s);
// state suff
bool _userSync() const;
bool _sysSync() const;
bool _setStateNotSafe(STATE newState);
static bool _readyNotSafe(STATE s);
static bool _userSyncNotSafe(STATE s);
static bool _sysSyncNotSafe(STATE s);
static bool _runningNotSafe(STATE s);
static NemoInterface::STATUS _status(STATE state);
static QString _toString(STATE s);
static QString _toString(NemoInterface::STATUS s);
static QString _localVersion;
QString _remoteVersion;
// impl functions
bool _addTilesImpl(
std::shared_ptr<QVector<std::shared_ptr<const Tile>>> pTileArray,
std::shared_ptr<const IDArray> pIdArray);
bool _removeTilesImpl(std::shared_ptr<const IDArray> pIdArray);
bool _clearTilesImpl();
// Worker functions.
static bool
_callAddTiles(const QVector<std::shared_ptr<const Tile>> &tileArray,
Dispatcher &d, Rosbridge &rb);
static bool _callClearTiles(Dispatcher &d, Rosbridge &rb);
static ProgressArray _callGetProgress(const IDArray &pIdArray, Dispatcher &d,
Rosbridge &rb);
static ProgressArray _callGetAllProgress(Dispatcher &d, Rosbridge &rb);
static QVector<std::shared_ptr<Tile>> _callGetAllTiles(Dispatcher &d,
Rosbridge &rb);
static QString _callGetVersion(Dispatcher &d, Rosbridge &rb);
static bool _callRemoveTiles(const IDArray &pIdArray, Dispatcher &d,
Rosbridge &rb);
// functions to manipulate _remoteTiles
bool _addTilesRemote(const QVector<std::shared_ptr<const Tile>> tileArray);
bool _addTilesRemote(const QVector<std::shared_ptr<Tile>> &tileArray);
void _removeTilesRemote(const IDArray &idArray);
void _clearTilesRemote();
void _clearTilesRemoteNotSafe();
// static and const members
static const char *_localVersion;
NemoInterface *const _parent;
std::atomic<STATE> _state;
std::atomic_bool _versionOK;
std::atomic_bool _progressTopicOK;
std::atomic_bool _heartbeatTopicOK;
std::atomic<CALL_NAME> _lastCall;
// thread safe members
ROSBridgePtr _pRosbridge;
Dispatcher _dispatcher;
// protected by mutex
mutable std::mutex _m;
STATE _state;
TileMap _remoteTiles;
TileMapConst _localTiles;
NemoInterface *const _parent;
Dispatcher _dispatcher;
QString _infoString;
QString _warningString;
// Members belonging to _parent->thread()
QTimer _timeoutTimer;
QTimer _syncTimer;
QTimer _restartTimer;
QNemoHeartbeat _lastHeartbeat;
FutureWatcher _futureWatcher;
};
QString NemoInterface::Impl::_localVersion("V_1.0");
const char *NemoInterface::Impl::_localVersion("V_1.0");
using StatusMap = std::map<NemoInterface::STATUS, QString>;
static StatusMap statusMap{
......@@ -206,8 +239,7 @@ static StatusMap statusMap{
NemoInterface::STATUS::WEBSOCKET_DETECTED, "Websocket Detected")};
NemoInterface::Impl::Impl(NemoInterface *p)
: _state(STATE::STOPPED), _versionOK(false), _progressTopicOK(false),
_heartbeatTopicOK(false), _parent(p) {
: _parent(p), _state(STATE::STOPPED) {
// ROS Bridge.
WimaSettings *wimaSettings =
......@@ -224,6 +256,7 @@ NemoInterface::Impl::Impl(NemoInterface *p)
this->start();
}
};
connect(connectionStringFact, &SettingsFact::rawValueChanged,
setConnectionString);
setConnectionString();
......@@ -235,29 +268,31 @@ NemoInterface::Impl::Impl(NemoInterface *p)
connect(this->_pRosbridge.get(), &Rosbridge::stateChanged, this->_parent,
[this] { this->_onRosbridgeStateChanged(); });
connect(&this->_futureWatcher, &FutureWatcher::finished, this->_parent,
[this] { this->_onFutureWatcherFinished(); });
connect(&this->_restartTimer, &QTimer::timeout, this->_parent,
[this] { this->_tryRestart(); });
connect(&this->_syncTimer, &QTimer::timeout, this->_parent,
[this] { this->_synchronizeIfNeccessary(); });
[this] { this->_synchronize(); });
static std::once_flag flag;
std::call_once(flag, [] { qRegisterMetaType<ProgressArray>(); });
}
NemoInterface::Impl::~Impl() { this->_pRosbridge->stop(); }
void NemoInterface::Impl::start() {
if (!running()) {
this->_setState(STATE::START_BRIDGE);
this->_doAction();
Lock lk(this->_m);
if (!_runningNotSafe(this->_state)) {
this->_setStateNotSafe(STATE::START_BRIDGE);
this->_doActionNotSafe();
}
}
void NemoInterface::Impl::stop() {
if (running()) {
this->_setState(STATE::STOPPED);
this->_doAction();
Lock lk(this->_m);
if (_runningNotSafe(this->_state)) {
this->_setStateNotSafe(STATE::STOPPED);
this->_doActionNotSafe();
}
}
......@@ -272,6 +307,8 @@ NemoInterface::Impl::addTiles(const TilePtrArray &tileArray) {
// copy unknown tiles
auto pTileArray = std::make_shared<QVector<std::shared_ptr<const Tile>>>();
auto pIdArray = std::make_shared<IDArray>();
Lock lk(this->_m);
for (const auto *pTile : tileArray) {
auto id = pTile->id();
const auto it = this->_localTiles.find(id);
......@@ -288,38 +325,36 @@ NemoInterface::Impl::addTiles(const TilePtrArray &tileArray) {
}
}
if (pTileArray->size() > 0) {
lk.unlock();
emit this->_parent->tilesChanged();
lk.lock();
}
// ready for send?
if (pTileArray->size() > 0 && (this->ready() || this->_userSync())) {
this->_setState(STATE::USER_SYNC);
this->_doAction();
// create add tiles command.
auto pTask = std::make_unique<Task>(
std::bind(&Impl::_callAddTiles, this, pTileArray));
// 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);
if (pTileArray->size() > 0 && (this->_readyNotSafe(this->_state) ||
this->_userSyncNotSafe(this->_state))) {
this->_setStateNotSafe(STATE::USER_SYNC);
this->_doActionNotSafe();
lk.unlock();
// create task.
auto pTask = std::make_unique<Task>([this, pTileArray, pIdArray] {
auto ret = this->_addTilesImpl(pTileArray, pIdArray);
if (ret) {
Lock lk(this->_m);
if (this->_isSynchronizedNotSafe()) {
this->_setStateNotSafe(STATE::READY);
this->_doActionNotSafe();
}
}
return ret;
});
// dispatch command.
ret = _dispatcher.dispatch(std::move(pTask));
auto progressFuture = ret.share();
_futureWatcher.setFuture(progressFuture);
return progressFuture;
auto ret = _dispatcher.dispatch(std::move(pTask));
return ret.share();
}
}
......@@ -338,6 +373,8 @@ NemoInterface::Impl::removeTiles(const IDArray &idArray) {
// copy known ids
auto pIdArray = std::make_shared<IDArray>();
Lock lk(this->_m);
for (const auto &id : idArray) {
const auto it = this->_localTiles.find(id);
Q_ASSERT(it != _localTiles.end());
......@@ -349,23 +386,37 @@ NemoInterface::Impl::removeTiles(const IDArray &idArray) {
}
}
if (pIdArray->size() > 0) {
lk.unlock();
emit this->_parent->tilesChanged();
lk.lock();
}
// ready for send?
if (pIdArray->size() > 0 && (this->ready() || this->_userSync())) {
if (pIdArray->size() > 0 && (this->_readyNotSafe(this->_state) ||
this->_userSyncNotSafe(this->_state))) {
this->_setState(STATE::USER_SYNC);
this->_doAction();
this->_setStateNotSafe(STATE::USER_SYNC);
this->_doActionNotSafe();
lk.unlock();
// create command.
auto cmd = std::make_unique<Task>(
std::bind(&Impl::_callRemoveTiles, this, pIdArray));
auto cmd = std::make_unique<Task>([this, pIdArray] {
auto ret = this->_removeTilesImpl(pIdArray);
if (ret) {
Lock lk(this->_m);
if (this->_isSynchronizedNotSafe()) {
this->_setStateNotSafe(STATE::READY);
this->_doActionNotSafe();
}
}
return ret;
});
// dispatch command and return.
auto ret = _dispatcher.dispatch(std::move(cmd));
auto sfut = ret.share();
_futureWatcher.setFuture(sfut);
return sfut;
}
}
......@@ -381,26 +432,40 @@ std::shared_future<QVariant> NemoInterface::Impl::clearTiles() {
// qDebug() << "clearTiles called";
// clear local tiles (_localTiles)
Lock lk(this->_m);
if (!_localTiles.empty()) {
this->_localTiles.clear();
lk.unlock();
emit this->_parent->tilesChanged();
lk.lock();
}
if (this->ready() || this->_userSync()) {
if (this->_readyNotSafe(this->_state) || this->_readyNotSafe(this->_state)) {
this->_setState(STATE::USER_SYNC);
this->_doAction();
this->_setStateNotSafe(STATE::USER_SYNC);
this->_doActionNotSafe();
lk.unlock();
// create command.
auto pTask =
std::make_unique<Task>(std::bind(&Impl::_callClearTiles, this));
auto pTask = std::make_unique<Task>([this] {
auto ret = this->_clearTilesImpl();
if (ret) {
Lock lk(this->_m);
if (this->_isSynchronizedNotSafe()) {
this->_setStateNotSafe(STATE::READY);
this->_doActionNotSafe();
}
}
return QVariant(ret);
});
// dispatch command and return.
auto ret = _dispatcher.dispatch(std::move(pTask));
auto sfut = ret.share();
_futureWatcher.setFuture(sfut);
return sfut;
return ret.share();
} else {
lk.unlock();
std::promise<QVariant> p;
p.set_value(QVariant(false));
return p.get_future();
......@@ -410,6 +475,7 @@ std::shared_future<QVariant> NemoInterface::Impl::clearTiles() {
TileArray NemoInterface::Impl::getTiles(const IDArray &idArray) const {
TileArray tileArray;
Lock lk(this->_m);
if (this->ready()) {
for (const auto &id : idArray) {
const auto it = _remoteTiles.find(id);
......@@ -440,6 +506,7 @@ TileArray NemoInterface::Impl::getTiles(const IDArray &idArray) const {
TileArray NemoInterface::Impl::getAllTiles() const {
TileArray tileArray;
Lock lk(this->_m);
if (this->ready()) {
for (const auto &entry : _remoteTiles) {
auto pTile = entry.second;
......@@ -467,6 +534,7 @@ TileArray NemoInterface::Impl::getAllTiles() const {
LogicalArray NemoInterface::Impl::containsTiles(const IDArray &idArray) const {
LogicalArray logicalArray;
Lock lk(this->_m);
for (const auto &id : idArray) {
const auto &it = _localTiles.find(id);
logicalArray.append(it != _localTiles.end());
......@@ -475,14 +543,22 @@ LogicalArray NemoInterface::Impl::containsTiles(const IDArray &idArray) const {
return logicalArray;
}
std::size_t NemoInterface::Impl::size() const { return _localTiles.size(); }
std::size_t NemoInterface::Impl::size() const {
Lock lk(this->_m);
return _localTiles.size();
}
bool NemoInterface::Impl::empty() const { return _localTiles.empty(); }
bool NemoInterface::Impl::empty() const {
Lock lk(this->_m);
return _localTiles.empty();
}
ProgressArray NemoInterface::Impl::getProgress() const {
ProgressArray progressArray;
if (this->_isSynchronized()) {
Lock lk(this->_m);
if (this->_isSynchronizedNotSafe()) {
for (const auto &entry : _remoteTiles) {
progressArray.append(
LabeledProgress{entry.second->progress(), entry.second->id()});
......@@ -500,7 +576,8 @@ ProgressArray NemoInterface::Impl::getProgress() const {
ProgressArray NemoInterface::Impl::getProgress(const IDArray &idArray) const {
ProgressArray progressArray;
if (this->_isSynchronized()) {
Lock lk(this->_m);
if (this->_isSynchronizedNotSafe()) {
for (const auto &id : idArray) {
const auto it = _remoteTiles.find(id);
if (it != _remoteTiles.end()) {
......@@ -522,173 +599,178 @@ ProgressArray NemoInterface::Impl::getProgress(const IDArray &idArray) const {
}
NemoInterface::STATUS NemoInterface::Impl::status() const {
Lock lk(this->_m);
return _status(this->_state);
}
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); }
bool NemoInterface::Impl::running() const {
Lock lk1(this->_m);
return _runningNotSafe(this->_state);
}
void NemoInterface::Impl::_onFutureWatcherFinished() {
if (this->ready() || this->_userSync() || this->_sysSync()) {
static long tries = 0;
auto lastTransactionSuccessfull = _futureWatcher.result().toBool();
if (!lastTransactionSuccessfull) {
++tries;
qCDebug(NemoInterfaceLog)
<< "last transaction unsuccessfull: " << _toString(_lastCall);
bool NemoInterface::Impl::ready() const {
Lock lk1(this->_m);
return _readyNotSafe(this->_state);
}
if (tries < 5) {
QTimer::singleShot(SYNC_RETRY_INTERVAL, this->_parent,
[this] { this->_trySynchronize(); });
} else {
_setWarningString("The last 5 transactions failed! Please check the "
"connection and consider reseting the connection.");
tries = 0;
}
} else {
tries = 0;
}
}
bool NemoInterface::Impl::_sysSync() const {
Lock lk1(this->_m);
return _sysSyncNotSafe(this->_state);
}
void NemoInterface::Impl::_onHeartbeatTimeout() {
this->_setState(STATE::HEARTBEAT_TIMEOUT);
this->_doAction();
Lock lk1(this->_m);
this->_setStateNotSafe(STATE::HEARTBEAT_TIMEOUT);
this->_doActionNotSafe();
}
void NemoInterface::Impl::_onRosbridgeStateChanged() {
auto state = this->_pRosbridge->state();
if (state == Rosbridge::STATE::CONNECTED) {
auto rbState = this->_pRosbridge->state();
if (rbState == Rosbridge::STATE::CONNECTED) {
Lock lk1(this->_m);
if (this->_state == STATE::START_BRIDGE ||
this->_state == STATE::WEBSOCKET_TIMEOUT) {
this->_setState(STATE::WEBSOCKET_DETECTED);
this->_doAction();
this->_setStateNotSafe(STATE::WEBSOCKET_DETECTED);
this->_doActionNotSafe();
}
} else if (state == Rosbridge::STATE::TIMEOUT) {
} else if (rbState == Rosbridge::STATE::TIMEOUT) {
Lock lk1(this->_m);
if (this->_state == STATE::TRY_SETUP || this->_state == STATE::READY ||
this->_state == STATE::WEBSOCKET_DETECTED ||
this->_state == STATE::HEARTBEAT_TIMEOUT) {
this->_setState(STATE::WEBSOCKET_TIMEOUT);
this->_doAction();
this->_setStateNotSafe(STATE::WEBSOCKET_TIMEOUT);
this->_doActionNotSafe();
}
}
}
bool NemoInterface::Impl::_userSync() const { return _userSync(this->_state); }
bool NemoInterface::Impl::_userSync() const {
Lock lk1(this->_m);
return _userSyncNotSafe(this->_state);
}
const QString &NemoInterface::Impl::infoString() const { return _infoString; }
const QString &NemoInterface::Impl::infoString() const {
Lock lk1(this->_m);
return _infoString;
}
const QString &NemoInterface::Impl::warningString() const {
Lock lk1(this->_m);
return _warningString;
}
void NemoInterface::Impl::_updateProgress(std::shared_ptr<ProgressArray> pArray,
std::promise<bool> promise) {
// qDebug() << "_updateProgress called";
bool NemoInterface::Impl::_updateProgress(const ProgressArray &pArray) {
ProgressArray copy;
bool error = false;
for (auto itLP = pArray->begin(); itLP != pArray->end();) {
Lock lk1(this->_m);
for (auto itLP = pArray.begin(); itLP != pArray.end(); ++itLP) {
auto it = _remoteTiles.find(itLP->id());
if (Q_LIKELY(it != _remoteTiles.end())) {
it->second->setProgress(itLP->progress());
++itLP;
copy.push_back(*itLP);
} else {
qCDebug(NemoInterfaceLog)
<< "_updateProgress(): tile with id " << itLP->id() << " not found.";
itLP = pArray->erase(itLP);
error = true;
}
}
lk1.unlock();
if (pArray->size() > 0) {
emit _parent->progressChanged(*pArray);
if (copy.size() > 0) {
emit _parent->progressChanged(copy);
}
promise.set_value(!error);
return !error;
}
void NemoInterface::Impl::_onHeartbeatReceived(const QNemoHeartbeat &hb,
std::promise<bool> promise) {
_lastHeartbeat = hb;
this->_timeoutTimer.start(NO_HEARTBEAT_TIMEOUT);
if (this->_state == STATE::TRY_SETUP) {
this->_setState(STATE::READY);
this->_doAction();
} else if (this->_state == STATE::HEARTBEAT_TIMEOUT) {
this->_setState(STATE::READY);
this->_doAction();
void NemoInterface::Impl::_onHeartbeatReceived(const QNemoHeartbeat &) {
INVM