Erstellen eines Erweiterungssystems in der Qt-Bibliothek - Teil 2

Zurück zum ersten Artikel möchte ich erläutern, wo die Notwendigkeit bestand, einen Erweiterungsmechanismus mit einer grafischen Oberfläche (GUI) zu entwickeln, und den Mechanismus zum Erstellen von Plug-Ins ausführlicher erläutern.

Es wurde der Auftrag erhalten, technologische Software zum Einstellen, Regeln, Steuern, Sammeln und Analysieren von Informationen von selbstfahrenden Pistolen (automatisierten Steuerungssystemen) des Motors auf dem russischen Betriebssystem zu entwickeln. Wenn der Austausch zwischen den selbstfahrenden Waffen und dem Technologieprogramm über die RS-232- oder RS422-Schnittstelle gemäß einem speziellen Austauschprotokoll erfolgt.

Nach Überprüfung und Analyse der Funktionen der Liste der russischen Betriebssysteme wurde das Betriebssystem AstraLinux ausgewählt. Dies ist ein spezielles System, das auf der Debian-Distribution basiert und zum umfassenden Schutz von Informationen und zum Aufbau sicherer automatisierter Systeme entwickelt wurde. Das Astra Linux-Betriebssystem wird in zwei Versionen entwickelt: Common Edition (kostenlos, allgemeiner Zweck) und Special Edition (kostenpflichtig, spezieller Zweck mit einer Reihe von Schutzalgorithmen).
Bei der Entwicklung von Software wurde die Qt-Bibliothek verwendet.

Die Software besteht aus Funktionsmodulen, mit denen Sie jeweils bestimmte Arbeiten an den Motoreinstellungen durchführen können.

Das Funktionsmodul ist ein Widget, das aus verschiedenen visuellen Komponenten, Grafiken und Tabellen besteht, in denen Motorparameter in einer benutzerfreundlichen Form angezeigt werden.


Funktionsbaustein „Dashboard“


Funktionsmodul, mit dem Sie Parameterwerte innerhalb akzeptabler Grenzen dynamisch steuern können


Funktionsbaustein zur Einstellung der Eigenschaften von selbstfahrenden Pistolen

Die entwickelte Software (technologisches Programm) war nur für einen bestimmten Motortyp vorgesehen. Für einen neuen Motortyp musste neue Software entwickelt werden, was zu einem erheblichen Anstieg der Arbeitskosten für Entwicklung, Test, Debugging und damit zu Verzögerungen bei der Implementierung dieser Software führte - obwohl diese Software bereits in der ACS-Entwicklungsphase gefragt war.

Um dieser kostspieligen Praxis der Entwicklung technologischer Software zu entkommen, wurde beschlossen, ein Softwarepaket zu entwickeln, das sich an jede Engine anpasst, deren ACS dasselbe Austauschprotokoll unterstützt.

Das Konzept bei der Entwicklung des Softwarepakets war die Möglichkeit, die Funktionalität basierend auf der Plug-In-Technologie mit Unterstützung für Grafikmodule zu erweitern.

Das Softwarepaket besteht aus drei Hauptteilen:

  1. Funktionskern des Komplexes
  2. Motor des Verlängerungssystems
  3. Plugin-Set

Zu den Kernfunktionen gehören die Gewährleistung eines zuverlässigen Datenaustauschs mit ACS und die Ausführung der folgenden Aufgaben:

  • RS232-Kommunikation über ein spezielles Protokoll
  • Kontinuierliche Überwachung der Motorparameterliste
  • Anforderung zur Änderung der Motorparameter
  • Leseanforderungen der Engine lesen
  • Parameter tabellarisch anzeigen
  • Verarbeiten von Anforderungen von Erweiterungen (Erstellen einer neuen Überwachungsliste nach Bedarf, einzelne Schreib- und Leseanforderungen)

Erweiterungssystem mit folgenden Funktionen:

  • Suche nach Erweiterungen
  • Erweiterungsgrafiken abrufen
  • Erweiterungsobjekte anzeigen
  • Die Aufgabe, Anforderungen (Signale) von Objekten mit dem Softwarekern zu verknüpfen

Jedes Plugin ist eine Fabrik von Objekten, und die Hauptfunktion des Plugins besteht darin, ein grafisches Objekt zu erstellen.

Die Aufgabe des Erweiterungssystems besteht darin, ein Objekt zu erhalten und es mit dem Kern des Programms zu verknüpfen (unter Verwendung bekannter Schnittstellen), das Objekt zu initialisieren und zu aktivieren.

Die Verbindung von Objekten mit dem Kernel erfolgt über eine virtuelle Klasse von Schnittstellen. Um eine neue Erweiterung zu entwickeln, müssen Sie nur die Schnittstellen kennen, die der Kern des Technologieprogramms unterstützt. Die Struktur des Programms ist in der folgenden Abbildung dargestellt.



Entwickeln Sie eine Plugin-Hierarchie.



Betrachten Sie die Hierarchie des vom Plugin erstellten grafischen Objekts. Da Sie bei der Arbeit mit Plugins Qt-Objekte bearbeiten sollten, ist die Hauptklasse wie in der Qt-Bibliothek die QObject-Klasse, die den Qt-Signal-Slot-Mechanismus unterstützt.

Die nächste Klasse ist QWidget - Sie müssen Ihre eigenen Grafikformulare erstellen.

Als nächstes benötigen Sie Ihre eigene Klasse von Schnittstellen, interfaceWidget. Dazu wird eine abstrakte Klasse erstellt, die von QWidget geerbt wird. In dieser Klasse werden Schnittstellen (Signale, Funktionen, Slots) deklariert, die das Hauptprojekt und das Plug-In-Objekt verbinden. Eine abstrakte Klasse bietet Schnittstellenunterstützung im Hauptprojekt.

Die MyFormQt-Klasse, die von der interfaceWidget-Schnittstellenklasse erbt und Schnittstellen definiert und in der die Grafiken und internen Funktionen des Moduls entwickelt werden. Dank dieses Vererbungsschemas unterstützt die MyFormQt-Klasse die Funktionalität der QWidget-Klasse und die entwickelten Kommunikationsschnittstellen mit dem Hauptanwendungsobjekt.

/** \class interfaceWidget \brief  ,      */ class interfaceWidget: public QWidget { public: /// \brief  virtual ~interfaceWidget() = default; /// \brief    /// \param ba,     /// \param ok,    virtual void getByte(QByteArray ba, bool ok) = 0; /// \brief     /// \param ba,     virtual void getRetrieveDate(QByteArray ba, bool ok) = 0; /// \brief     /// \param fl,   virtual void successfullyWritten(bool fl) = 0; /// \brief      /// \param ok     /// \return        virtual QVector<QString > regParam(bool &ok) = 0; signals: /// \brief       /// \param       virtual void signal_writeByteByName(QVector<TVARPARAM > vecParam) = 0; /// \brief      /// \param nameParam   virtual void signal_getByteByName(QVector<QString > nameParam) = 0; /// \brief      /// \param addr       /// \param ndata -    virtual void signal_getByteByAddress(quint32 addr, quint32 ndata) = 0; /// \brief       /// \param addr      /// \param ba    virtual void signal_writeByteByAddress(quint32 addr, QByteArray ba) = 0; /// \brief      /// \param fl, true  , false   virtual void signal_enableMonitoring(bool fl) = 0; }; 

Eine solche Hierarchie ermöglicht es, das Problem der rautenförmigen Vererbung zu umgehen und gleichzeitig den Signalschlitzmechanismus für das erzeugte Objekt beizubehalten, was ein wichtiger Punkt in der vorgeschlagenen Technologie für die Entwicklung technologischer Software ist.

Initialisierungs- und Datenaustauschprozess. Das gesamte Projekt basiert auf einem MDI-Bereich. Daher werden alle Plugins als separates MDI-Fenster geladen.

Das Factory-Plug-In erstellt ein Objekt der Klasse MyFormQt, konvertiert den Zeiger auf das erstellte Objekt in einen Zeiger auf QObject und übergibt es an das Technologieprogramm, in dem das Objekt mithilfe der Operation dynamic_cast in ein Objekt der Klasse interfaceWidget konvertiert wird, wodurch wir vollen Zugriff auf die grafische Form und die Schnittstellen dieses Objekts erhalten .

Factory-Funktion (Erstellen eines grafischen Funktionsobjekts im Plugin).

 //------------------------------------------------------------------ QObject *screenOnlinePlugin::getPluginWidget() { MyFormQt *screen = new MyFormQt(); return qobject_cast<QObject *>(screen); //    } //------------------------------------------- 

Die Funktion, ein grafisches Funktionsobjekt in einem technologischen Programm (Kern) zu erhalten und zu initiieren.

 //----------------------------------------------------------------- void PluginSystem::showPluginWidget(QString dirFabrica) { QMdiSubWindow *sWPS = new QMdiSubWindow; pQtTM->m_pma->addSubWindow(sWPS); sWPS->setAttribute(Qt::WA_DeleteOnClose, true); //--------  QPluginLoader loader(dirFabrica); //   QObject *pobj = qobject_cast<QObject*>(loader.instance()); if(!pobj) return; pluginInterface *fabrica = qobject_cast<pluginInterface *>(pobj); if(!fabric) return; QObject *ob = fabrica→getPluginWidget(); //    if(!ob) return; interfaceWidget *interFaceW = dynamic_cast<interfaceWidget *>(ob); if(!interFaceW) return; delete fabrica; //   connect(interFaceW, SIGNAL(), this, SLOT()); sWPS->setWidget(interFaceW); sWPS->show(); //   QVector<QString > vecParam; vecParam = interFaceW→regParam(paramOK); //   if(paramOK) regParamList(vecPlugin[i].namePlugin ,vecParam); } //-------------------------------------------------------------------------------- 

Ein Objekt der interfaceWidget-Klasse (Grafikfunktionsobjekt) wird im erstellten QmdiSubWindow-Fenster platziert und dadurch als untergeordnetes Element festgelegt.

Verbinden Sie anschließend die Signale und Slots des Objekts mit den Signalen und Slots des Kerns des Technologieprogramms und der letzten Stufe der Fensteranzeige mithilfe der show () -Methode. Wenn Sie das QmdiSubWindow-Fenster schließen, wird auch das Objekt der interfaceWidget-Klasse gelöscht, da die DeleteOnClose-Eigenschaft im Voraus für das SubWindow festgelegt wurde, in dem das Objekt platziert wurde.

Der Datenaustausch zwischen grafischen Funktionsobjekten und einem technologischen Programm erfolgt mithilfe von Daten-Marshalling und zwei Modi:
• Einzelmodus (Anfrage-Antwort);
• Im Überwachungsmodus empfangen wir ständig Daten mit einem Zeitraum, der durch den Mechanismus des Datenaustauschs mit dem Zielgerät bestimmt wird.

Beim Marshaling werden Daten in ein Format konvertiert, das zum Speichern oder Übertragen geeignet ist. Es wird verwendet, wenn Informationen zwischen verschiedenen Teilen eines Programms oder von einem Programm zu einem anderen übertragen werden müssen.

In einem einzelnen Modus drückt der Benutzer eine Taste in einem Grafikfunktionsobjekt (Widget) und generiert ein Signal mit einer Liste von Parametern, deren Daten im Zielgerät (ACS) gelesen und an das Grafikfunktionsobjekt übertragen werden sollen. Der Datenaustauschmechanismus im Hauptprogramm verarbeitet das Signal und beginnt, RS-232-Daten von den selbstfahrenden Pistolen anzufordern. Die empfangenen Daten werden in QbyteArray verpackt und mit einem Signal an ein Grafikobjekt gesendet. Das Objekt verfügt über eine Liste der angeforderten Parameter und kennt daher deren Typen, entpackt die in QbyteArray enthaltenen Daten und zeigt sie in Form von Grafiken und Tabellen sowie speziellen grafischen Widgets (Pfeilanzeigen, digitale Anzeigen, hintergrundbeleuchtete Schaltflächen usw.) an.

Im Überwachungsmodus fordert das System bei der Initialisierung des Plug-Ins sofort die erforderliche Liste von Parametern für das Plug-In an und liest während der ständigen Überwachung seiner Parameter zusätzliche Parameter für das Plug-In und gibt sie in Form eines Bytepakets für jeden Datenaustauschzyklus aus. Die Dauer des Datenaustauschzyklus hängt von der Anzahl der angeforderten Parameter ab.

Derzeit werden Tests durchgeführt und gleichzeitig Gruppen von Plug-Ins für verschiedene Aufgaben entwickelt.

Es wurde eine Plugin-Vorlage erstellt, die die Entwicklung neuer Plugins beschleunigt. Unter Verwendung der Plug-In-Vorlage für die Entwicklung eines neuen Funktionsmoduls ist es erforderlich, ein neues Grafikformular zu erstellen und Datenverarbeitungs- und Visualisierungsalgorithmen zu implementieren.

Es wurden physische Treibersoftwaremodule für die kabelgebundene RS-232-Schnittstelle sowie drahtloses WIFI und Bluetooth entwickelt.

Bisher arbeitet das Softwarepaket im 2-Kanal-Modus, dh es kann gleichzeitig mit 2 selbstfahrenden Pistolen arbeiten (dies war die Anforderung des Kunden). Funktionsmodul-Plugins werden vom Benutzer an einen der beiden Kanäle angeschlossen.

Während des Tests konnten wir gleichzeitig 12 Plugins starten, die vom Kernel erfolgreich verarbeitet wurden. Und selbst 12 Plugins sind nicht die Grenze für dieses System. Durch das Qt-Doppelpuffersystem wird der Zeitaufwand für das Zeichnen von Plug-Ins reduziert und das Flackern von Plug-Ins verhindert. Wenn Sie also in Zukunft die Anzahl der Plug-Ins erhöhen, wird der Datenaustausch nur über die RS-232-Schnittstelle erfolgen. Obwohl die Praxis zeigt, dass beim Debuggen, Optimieren und Testen einer ACS-Engine 3-4 gleichzeitig funktionierende Plug-Ins ausreichen.

Als Ergebnis unserer Arbeit erhielten wir ein Softwarepaket für die schnelle Entwicklung von Technologieprogrammen zum Tunen, Inbetriebnehmen und Testen von selbstfahrenden Pistolen für verschiedene Motortypen (mechatronische Systeme).

Es wurden 2 Sätze von Plug-Ins für verschiedene Motortypen entwickelt.

Durch das Anschließen einer Reihe von Plug-Ins für einen bestimmten Typ von selbstfahrenden Pistolen an das Softwarepaket erhalten wir ein multifunktionales Programm zum Konfigurieren, Inbetriebnehmen und Testen dieser Art von selbstfahrenden Pistolen.



In Zukunft planen wir, einen Artikel über die Entwicklung eigener Grafik-Widgets für bestimmte Aufgaben und einen separaten Artikel über das Layout von Grafikobjekten zu schreiben.

Source: https://habr.com/ru/post/de457744/


All Articles