Criando um sistema de extensão na biblioteca Qt - parte 2

Voltando ao primeiro artigo, gostaria de explicar onde surgiu a necessidade de desenvolver um mecanismo de extensão com uma interface gráfica (GUI) e explicar mais detalhadamente o mecanismo de criação de plug-ins.

Foi recebida uma tarefa para desenvolver um software tecnológico para ajustar, regular, controlar, coletar e analisar informações de armas de autopropulsão (sistemas de controle automatizado) do motor no sistema operacional russo. Onde a troca entre as armas de autopropulsão e o programa tecnológico é realizada via interface RS-232 ou RS422, de acordo com um protocolo de troca especial.

Após revisar e analisar os recursos da lista de sistemas operacionais russos, foi escolhido o sistema operacional AstraLinux. Este é um sistema de propósito especial baseado na distribuição Debian, projetado para proteger informações de forma abrangente e construir sistemas automatizados seguros. O sistema operacional Astra Linux está sendo desenvolvido em duas versões: Common Edition (gratuita, de uso geral) e Special Edition (paga, de finalidade especial com um conjunto de algoritmos de proteção).
Ao desenvolver o software, a biblioteca Qt foi usada.

O software consiste em módulos funcionais, cada um dos quais permite executar um trabalho específico nas configurações do mecanismo.

O módulo funcional é um widget que consiste em vários componentes visuais, gráficos e tabelas, em que os parâmetros do mecanismo são exibidos de forma amigável.


Módulo funcional "Painel"


Módulo funcional que permite controlar dinamicamente os valores dos parâmetros dentro de limites aceitáveis


Módulo de função para definir as características de armas de autopropulsão

O software desenvolvido (programa tecnológico) foi destinado apenas a um determinado tipo de mecanismo. Para um novo tipo de mecanismo, foi necessário desenvolver um novo software, o que levou a um aumento significativo nos custos de mão-de-obra para o desenvolvimento, teste, depuração e, como resultado, atrasos na implementação desse software - apesar do fato de que esse software já estava sendo solicitado no estágio de desenvolvimento do ACS.

Para se afastar dessa prática onerosa de desenvolvimento de software tecnológico, foi decidido desenvolver um pacote de software que se adaptará a qualquer mecanismo cujo ACS suporte o mesmo protocolo de troca.

O conceito no desenvolvimento do pacote de software era a possibilidade de expandir a funcionalidade baseada na tecnologia de plug-in, com suporte para módulos gráficos.

O pacote de software consiste em três partes principais:

  1. Núcleo funcional do complexo
  2. Mecanismo do sistema de extensão
  3. Conjunto de plugins

As principais funções incluem garantir a troca confiável de dados com o ACS e executar as seguintes tarefas:

  • Comunicação RS232 usando um protocolo especial
  • Monitoramento contínuo da lista de parâmetros do motor
  • Solicitação de alteração de parâmetro do mecanismo
  • Ler solicitações de leitura do mecanismo
  • Exibir parâmetros em forma de tabela
  • Processando solicitações de extensões (criando uma nova lista de monitoramento conforme necessário, solicitações únicas de gravação e leitura)

Sistema de expansão com as seguintes funções:

  • Pesquisar extensões
  • Obtendo gráficos de extensão
  • Exibir objetos de extensão
  • A tarefa de vincular solicitações (sinais) de objetos ao núcleo do software

Cada plug-in é uma fábrica de objetos, e a principal função do plug-in é criar um objeto gráfico.

A tarefa do sistema de extensão é obter um objeto e associá-lo ao núcleo do programa (usando interfaces conhecidas), inicializar e ativar o objeto.

A conexão de objetos com o kernel ocorre usando uma classe virtual de interfaces. Para desenvolver uma nova extensão, você só precisa conhecer as interfaces suportadas pelo núcleo do programa de tecnologia. A estrutura do programa é apresentada na figura a seguir.



Desenvolva uma hierarquia de plugins.



Considere a hierarquia do objeto gráfico criado pelo plug-in. Como ao trabalhar com plugins, você deve operar em objetos Qt, a classe principal, como na biblioteca Qt, será a classe QObject, que suporta o mecanismo de slot de sinal Qt.

A próxima classe é QWidget - é necessário criar suas próprias formas gráficas.

Em seguida, você precisa de sua própria classe de interfaces, interfaceWidget. Para isso, é criada uma classe abstrata, que será herdada do QWidget. Nesta classe, são declaradas interfaces (sinais, funções, slots) que conectam o projeto principal e o objeto do plug-in. Uma classe abstrata fornece suporte de interface no projeto principal.

A classe MyFormQt, que herda da classe de interface interfaceWidget e define as interfaces e nas quais os gráficos e a funcionalidade interna do módulo são desenvolvidos. Graças a esse esquema de herança, a classe MyFormQt suporta a funcionalidade da classe QWidget e as interfaces de comunicação desenvolvidas com o objeto principal do aplicativo.

/** \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; }; 

Essa hierarquia permite contornar o problema da herança em forma de diamante, mantendo o mecanismo do slot de sinal para o objeto criado, que é um ponto importante na tecnologia proposta para o desenvolvimento de software tecnológico.

Processo de inicialização e troca de dados: todo o projeto é baseado em uma área MDI; portanto, todos os plugins serão carregados como uma janela MDI separada.

O plug-in de fábrica cria um objeto da classe MyFormQt, converte o ponteiro para o objeto criado em um ponteiro para QObject e o passa para o programa tecnológico, onde o objeto é convertido usando a operação dynamic_cast em um objeto da classe interfaceWidget, como resultado, obtemos acesso total à forma gráfica e às interfaces desse objeto .

Função de fábrica (criando um objeto de função gráfica no plug-in).

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

A função de obter e iniciar um objeto funcional gráfico em um programa tecnológico (núcleo).

 //----------------------------------------------------------------- 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); } //-------------------------------------------------------------------------------- 

Um objeto da classe interfaceWidget (objeto de função gráfica) é colocado na janela QmdiSubWindow criada, configurando-o como filho.

Em seguida, conecte (conecte) os sinais e slots do objeto com os sinais e slots do núcleo do programa tecnológico e o último estágio da exibição da janela usando o método show (). Quando você fecha a janela QmdiSubWindow, o objeto da classe interfaceWidget também será excluído, porque a propriedade DeleteOnClose foi definida anteriormente para a subWindow na qual o objeto foi colocado.

A troca de dados entre objetos funcionais gráficos e um programa tecnológico ocorre usando o empacotamento de dados e dois modos:
• Modo único (solicitação-resposta);
• Modo de monitoramento, recebemos dados constantemente com um período determinado pelo mecanismo de troca de dados com o dispositivo de destino;

Marshaling é o processo de conversão de dados em um formato adequado para armazenamento ou transmissão. É usado quando as informações precisam ser transferidas entre diferentes partes de um programa ou de um programa para outro.

Em um único modo, o usuário pressiona um botão em um objeto de função gráfica (widget) gera um sinal contendo uma lista de parâmetros, cujos dados devem ser lidos no dispositivo de destino (ACS) e transferidos para o objeto de função gráfica. O mecanismo de troca de dados no programa principal processa o sinal e começa a solicitar dados RS-232 das armas de autopropulsão, os dados recebidos são empacotados em QbyteArray e enviados com um sinal para um objeto gráfico. O objeto possui uma lista de parâmetros solicitados e, portanto, conhece seus tipos, descompacta os dados contidos no QbyteArray e os exibe na forma de gráficos e tabelas e widgets gráficos especializados (indicadores de seta, indicadores digitais, botões de contraluz etc.).

No modo de monitoramento, quando o plug-in é inicializado, o sistema solicita imediatamente a lista de parâmetros necessária para o plug-in e, durante o monitoramento constante de seus parâmetros, lê parâmetros adicionais para o plug-in e os fornece como pacote de bytes a cada ciclo de troca de dados. O período do ciclo de troca de dados depende do número de parâmetros solicitados.

No momento, os testes estão em andamento e, ao mesmo tempo, o desenvolvimento de grupos de plug-ins para tarefas diferentes.

Foi criado um modelo de plug-in que acelera o processo de desenvolvimento de novos plug-ins. Usando o modelo de plug-in para o desenvolvimento de um novo módulo funcional, é necessário criar uma nova forma gráfica e implementar algoritmos de processamento e visualização de dados.

Foram desenvolvidos módulos de software de driver físico para a interface RS-232 com fio e WIFI e Bluetooth sem fio.

Até a presente data, o pacote de software opera no modo de 2 canais, ou seja, pode funcionar simultaneamente com 2 pistolas de autopropulsão (esse era o requisito do cliente). Os plugins de módulos funcionais são conectados a qualquer um dos 2 canais pelo usuário.

Durante o teste, conseguimos lançar simultaneamente 12 plug-ins que foram processados ​​com sucesso pelo kernel. E até 12 plugins não são o limite para este sistema. Devido ao sistema de buffer duplo Qt, o tempo gasto no desenho de plug-ins é reduzido e evita que os plug-ins pisquem; portanto, ao aumentar o número de plug-ins no futuro, o ônus principal será apenas na troca de dados pela interface RS-232. Embora a prática mostre que durante a depuração, ajuste e teste de um mecanismo ACS, 3-4 plug-ins que funcionam ao mesmo tempo são suficientes.

Como resultado do trabalho, recebemos um pacote de software para o rápido desenvolvimento de programas tecnológicos destinados a ajustar, comissionar e testar armas de autopropulsão para vários tipos de motores (sistemas mecatrônicos).

Foram desenvolvidos 2 conjuntos de plug-ins para diferentes tipos de motores.

Ao conectar um conjunto de plug-ins para um tipo específico de pistola automotora ao pacote de software, obtemos um programa multifuncional para configurar, comissionar e testar esse tipo de pistola automotora.



No futuro, planejamos escrever um artigo sobre o desenvolvimento de nossos próprios widgets gráficos, para tarefas específicas e um artigo separado sobre o layout de objetos gráficos.

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


All Articles