Browse Source

Fix/Rework signal compress code to fix signal loss

QGC4.4
DonLakeFlyer 4 years ago committed by Don Gagne
parent
commit
e29da008bb
  1. 96
      src/QGCApplication.cc
  2. 115
      src/QGCApplication.h

96
src/QGCApplication.cc

@ -969,3 +969,99 @@ QString QGCApplication::cachedAirframeMetaDataFile(void) @@ -969,3 +969,99 @@ QString QGCApplication::cachedAirframeMetaDataFile(void)
QDir airframeDir = QFileInfo(settings.fileName()).dir();
return airframeDir.filePath(QStringLiteral("PX4AirframeFactMetaData.xml"));
}
/// Returns a signal index that is can be compared to QMetaCallEvent.signalId
int QGCApplication::CompressedSignalList::_signalIndex(const QMetaMethod & method)
{
if (method.methodType() != QMetaMethod::Signal) {
qWarning() << "Internal error: QGCApplication::CompressedSignalList::_signalIndex not a signal" << method.methodType();
return -1;
}
int index = -1;
const QMetaObject* metaObject = method.enclosingMetaObject();
for (int i=0; i<=method.methodIndex(); i++) {
if (metaObject->method(i).methodType() != QMetaMethod::Signal) {
continue;
}
index++;
}
return index;
}
void QGCApplication::CompressedSignalList::add(const QMetaMethod & method)
{
const QMetaObject* metaObject = method.enclosingMetaObject();
int signalIndex = _signalIndex(method);
if (signalIndex != -1 && !contains(metaObject, signalIndex)) {
_signalMap[method.enclosingMetaObject()].insert(signalIndex);
}
}
void QGCApplication::CompressedSignalList::remove(const QMetaMethod & method)
{
int signalIndex = _signalIndex(method);
const QMetaObject* metaObject = method.enclosingMetaObject();
if (signalIndex != -1 && _signalMap.contains(metaObject) && _signalMap[metaObject].contains(signalIndex)) {
_signalMap[metaObject].remove(signalIndex);
if (_signalMap[metaObject].count() == 0) {
_signalMap.remove(metaObject);
}
}
}
bool QGCApplication::CompressedSignalList::contains(const QMetaObject* metaObject, int signalIndex)
{
return _signalMap.contains(metaObject) && _signalMap[metaObject].contains(signalIndex);
}
void QGCApplication::addCompressedSignal(const QMetaMethod & method)
{
_compressedSignals.add(method);
}
void QGCApplication::removeCompressedSignal(const QMetaMethod & method)
{
_compressedSignals.remove(method);
}
bool QGCApplication::compressEvent(QEvent*event, QObject* receiver, QPostEventList* postedEvents)
{
if (event->type() != QEvent::MetaCall) {
return QApplication::compressEvent(event, receiver, postedEvents);
}
QMetaCallEvent* mce = static_cast<QMetaCallEvent*>(event);
if (!mce->sender() || !_compressedSignals.contains(mce->sender()->metaObject(), mce->signalId())) {
return QApplication::compressEvent(event, receiver, postedEvents);
}
for (QPostEventList::iterator it = postedEvents->begin(); it != postedEvents->end(); ++it) {
QPostEvent &cur = *it;
if (cur.receiver != receiver || cur.event == 0 || cur.event->type() != event->type()) {
continue;
}
QMetaCallEvent *cur_mce = static_cast<QMetaCallEvent*>(cur.event);
if (cur_mce->sender() != mce->sender() || cur_mce->signalId() != mce->signalId() || cur_mce->id() != mce->id()) {
continue;
}
/* Keep The Newest Call */
// We can't merely qSwap the existing posted event with the new one, since QEvent
// keeps track of whether it has been posted. Deletion of a formerly posted event
// takes the posted event list mutex and does a useless search of the posted event
// list upon deletion. We thus clear the QEvent::posted flag before deletion.
struct EventHelper : private QEvent {
static void clearPostedFlag(QEvent * ev) {
(&static_cast<EventHelper*>(ev)->t)[1] &= ~0x8001; // Hack to clear QEvent::posted
}
};
EventHelper::clearPostedFlag(cur.event);
delete cur.event;
cur.event = event;
return true;
}
return false;
}

115
src/QGCApplication.h

@ -98,14 +98,18 @@ public: @@ -98,14 +98,18 @@ public:
QTranslator& qgcJSONTranslator(void) { return _qgcTranslatorJSON; }
static QString cachedParameterMetaDataFile(void);
static QString cachedAirframeMetaDataFile(void);
void setLanguage();
QQuickItem* mainRootWindow();
uint64_t msecsSinceBoot(void) { return _msecsElapsedTime.elapsed(); }
/// Registers the signal such that only the last duplicate signal added is left in the queue.
void addCompressedSignal(const QMetaMethod & method);
void removeCompressedSignal(const QMetaMethod & method);
static QString cachedParameterMetaDataFile(void);
static QString cachedAirframeMetaDataFile(void);
public slots:
/// You can connect to this slot to show an information message box from a different thread.
void informationMessageBoxOnMainThread(const QString& title, const QString& msg);
@ -178,6 +182,8 @@ private: @@ -178,6 +182,8 @@ private:
void _checkForNewVersion ();
void _exitWithError (QString errorMessage);
// Overrides from QApplication
bool compressEvent(QEvent *event, QObject *receiver, QPostEventList *postedEvents) override;
bool _runningUnitTests; ///< true: running unit tests, false: normal app
static const int _missingParamsDelayedDisplayTimerTimeout = 1000; ///< Timeout to wait for next missing fact to come in before display
@ -204,102 +210,29 @@ private: @@ -204,102 +210,29 @@ private:
QList<QPair<QString /* title */, QString /* message */>> _delayedAppMessages;
static const char* _settingsVersionKey; ///< Settings key which hold settings version
static const char* _deleteAllSettingsKey; ///< If this settings key is set on boot, all settings will be deleted
class CompressedSignalList {
Q_DISABLE_COPY(CompressedSignalList)
/// Unit Test have access to creating and destroying singletons
friend class UnitTest;
private:
/*! Keeps a list of singal indices for one or more meatobject classes.
* The indices are signal indices as given by QMetaCallEvent.signalId.
* On Qt 5, those do *not* match QMetaObject::methodIndex since they
* exclude non-signal methods. */
class SignalList {
Q_DISABLE_COPY(SignalList)
typedef QMap<const QMetaObject *, QSet<int> > T;
T m_data;
/*! Returns a signal index that is can be compared to QMetaCallEvent.signalId. */
static int signalIndex(const QMetaMethod & method) {
Q_ASSERT(method.methodType() == QMetaMethod::Signal);
int index = -1;
const QMetaObject * mobj = method.enclosingMetaObject();
for (int i = 0; i <= method.methodIndex(); ++i) {
if (mobj->method(i).methodType() != QMetaMethod::Signal) continue;
++ index;
}
return index;
}
public:
SignalList() {}
void add(const QMetaMethod & method) {
m_data[method.enclosingMetaObject()].insert(signalIndex(method));
}
void remove(const QMetaMethod & method) {
T::iterator it = m_data.find(method.enclosingMetaObject());
if (it != m_data.end()) {
it->remove(signalIndex(method));
if (it->empty()) m_data.erase(it);
}
}
bool contains(const QMetaObject * metaObject, int signalId) {
T::const_iterator it = m_data.find(metaObject);
return it != m_data.end() && it.value().contains(signalId);
}
};
CompressedSignalList() {}
SignalList m_compressedSignals;
void add (const QMetaMethod & method);
void remove (const QMetaMethod & method);
bool contains (const QMetaObject * metaObject, int signalIndex);
public:
void addCompressedSignal(const QMetaMethod & method) { m_compressedSignals.add(method); }
void removeCompressedSignal(const QMetaMethod & method) { m_compressedSignals.remove(method); }
private:
static int _signalIndex(const QMetaMethod & method);
private:
struct EventHelper : private QEvent {
static void clearPostedFlag(QEvent * ev) {
(&static_cast<EventHelper*>(ev)->t)[1] &= ~0x8001; // Hack to clear QEvent::posted
}
QMap<const QMetaObject*, QSet<int> > _signalMap;
};
bool compressEvent(QEvent *event, QObject *receiver, QPostEventList *postedEvents) {
if (event->type() != QEvent::MetaCall)
return QApplication::compressEvent(event, receiver, postedEvents);
QMetaCallEvent *mce = static_cast<QMetaCallEvent*>(event);
if (mce->sender() && !m_compressedSignals.contains(mce->sender()->metaObject(), mce->signalId())) {
return false;
}
for (QPostEventList::iterator it = postedEvents->begin(); it != postedEvents->end(); ++it) {
QPostEvent &cur = *it;
if (cur.receiver != receiver || cur.event == 0 || cur.event->type() != event->type())
continue;
QMetaCallEvent *cur_mce = static_cast<QMetaCallEvent*>(cur.event);
if (cur_mce->sender() != mce->sender() || cur_mce->signalId() != mce->signalId() ||
cur_mce->id() != mce->id())
continue;
if (true) {
/* Keep The Newest Call */
// We can't merely qSwap the existing posted event with the new one, since QEvent
// keeps track of whether it has been posted. Deletion of a formerly posted event
// takes the posted event list mutex and does a useless search of the posted event
// list upon deletion. We thus clear the QEvent::posted flag before deletion.
EventHelper::clearPostedFlag(cur.event);
delete cur.event;
cur.event = event;
} else {
/* Keep the Oldest Call */
delete event;
}
return true;
}
return false;
}
CompressedSignalList _compressedSignals;
static const char* _settingsVersionKey; ///< Settings key which hold settings version
static const char* _deleteAllSettingsKey; ///< If this settings key is set on boot, all settings will be deleted
/// Unit Test have access to creating and destroying singletons
friend class UnitTest;
};
/// @brief Returns the QGCApplication object singleton.

Loading…
Cancel
Save