Pull to refresh

Создание системы расширения на библиотеке Qt — Часть 2

Reading time8 min
Views6.2K
Возвращаясь к первой статье хочется объяснить откуда появилась необходимость разработки механизма расширения с графическим интерфейсом (GUI) и подробней объяснить механизм создания плагинов.

Было получено задание на разработку технологического программного обеспечения для настройки, регулирования, контроля, сбора и анализа информации САУ(системы автоматизированного управления) двигателя, на российской операционной системе. Где обмен между САУ и технологической программой осуществляется по интерфейсу RS-232 или RS422, по специальному протоколу обмена.

После рассмотрения и анализа возможностей списка российских операционных систем была выбрана операционная система AstraLinux. Это система специального назначения на базе дистрибутива Debian, созданная для комплексной защиты информации и построения защищённых автоматизированных систем. Операционная система Астра Линукс разрабатывается в двух модификациях: Common Edition(бесплатная, общего назначения) и Special Edition(платная, специального назначения с пакетом алгоритмов защиты).
При разработке программного обеспечения была использована библиотека Qt.

Программное обеспечение состоит из функциональных модулей, каждый из которых позволяет производить специфичные работы по настройки двигателя.

Функциональный модуль представляет собой виджет состоящий из различных визуальных компонентов, графиков и таблиц, где в удобном для пользователя виде отображаются параметры двигателя.


Функциональный модуль “Приборная панель”


Функциональный модуль, позволяющий динамически контролировать значения параметров в допустимых границах


Функциональный модуль для настройки характеристик САУ

Разработанное ПО (технологическая программа) было предназначено только для определенного типа двигателя. Для нового типа двигателя приходилось разрабатывать новое ПО, что приводило к значительному увеличению трудозатрат на разработку, тестирование, отладку и, как следствие, задержкам на внедрение данного ПО — при том, что, подобное ПО востребовано уже на этапе разработки САУ.

Для того, чтобы уйти от подобной затратной практики разработки технологического программного обеспечения было принято решение о разработки программного комплекса, который будет адаптироваться к любому двигателю, САУ которого поддерживает одинаковый протокол обмена.

Концепцией при разработке программного комплекса служила возможность расширения функциональности на базе технологии плагинов с поддержкой графических модулей.

Программный комплекс состоит из трех основных частей:

  1. Функциональное ядро комплекса
  2. Механизм системы расширений
  3. Набор плагинов

В функции ядра входит обеспечение надежного обмен данными с САУ и выполнение следующих задач:

  • Обмен информацией по интерфейсу RS232 с использованием специального протокола
  • Непрерывный мониторинг списка параметров двигателя
  • Запрос на изменение параметров двигателя
  • Запросы на чтения параметров двигателя
  • Отображение параметров виде табличной формы
  • Обработка запросов от расширений(создания нового списка мониторинга по необходимости, одиночные запросы на запись и считывание)

Система расширения со следующими функциями:

  • Поиск расширений
  • Получение графических объектов расширений
  • Отображение объектов расширений
  • Задача по связыванию запросов(сигналов) от объектов к ядру ПО

Каждый плагин является фабрикой объектов, и основной функцией плагина является создание графического объекта.

Задачей системы расширения является получение объекта и связывание его с ядром программы (с помощью известных интерфейсов ), инициализация и активация объекта.

Связь объектов с ядром происходит с помощью виртуального класса интерфейсов. Для разработки нового расширения необходимо знать только интерфейсы которые поддерживает ядро технологической программы. Структура программы представлена на след рисунке.



Разработка иерархия плагина.



Рассмотрим иерархию графического объекта, создаваемого плагином. Так как при работе с плагинами следует оперировать объектами Qt, основным классом, как и в библиотеке Qt, будет класс QObject, который поддерживает, сигнально-слотовый механизм Qt.

Следующим классом является QWidget — он необходим для создания своих графических форм.

Далее необходим свой класс интерфейсов interfaceWidget. Для этого создаётся абстрактный класс, который будет наследоваться от QWidget. В этом классе объявляются интерфейсы (сигналы, функции, слоты) которые будут связывать основной проект и объект плагина. Абстрактный класс обеспечивает поддержку интерфейса в основном проекте.

Класс MyFormQt, который наследуется от класса интерфейсов interfaceWidget и определяет интерфейсы и и в котором разрабатывается графика и внутренняя функциональность модуля. Благодаря такой схеме наследования класс MyFormQt, поддерживает функционал класса QWidget и разработанные интерфейсы связи с основным объектом приложения.

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

Такая иерархия позволяет обойти проблему ромбовидного наследования, сохранив сигнально-слотовый механизм для создаваемого объекта, что является важным моментом в предлагаемой технологии разработки технологического программного обеспечения.

Процесс инициализации и обмена данными.Весь проект основан на MDI области следственно все плагины будут загружаться в виде отдельного MDI окна.

Плагин-фабрика создает объект класса MyFormQt, преобразует указатель на созданный объект к указателю на QObject и передает его в технологическую программу, где следует преобразование объекта c помощью операции dynamic_cast на объекта класса interfaceWidget, в следствии чего получаем полный доступ к графической форме и интерфейсам этого объекта.

Функция фабрики (создание графического функционального объекта в плагине).

//------------------------------------------------------------------
QObject *screenOnlinePlugin::getPluginWidget()
{
   MyFormQt *screen = new MyFormQt();
   return qobject_cast<QObject *>(screen); // Преобразование в объект
}
//-------------------------------------------

Функция получения и инициации графического функционального объекта в технологической программе (ядро).

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

Объект класса interfaceWidget (графический функциональный объект) помещается на созданное окно QmdiSubWindow, тем самым устанавливая его дочерним.

Далее связываются(connect) сигналы и слоты объекта с сигналами и слотами ядра технологической программы и последним этапом показ окна методом show(). При закрытия окна QmdiSubWindow, также будет удален объект класса interfaceWidget, т. к. заранее для subWindow в котором помещен объект было установлено свойство DeleteOnClose.

Обмен данными между графическими функциональными объектами и технологической программой проходит используя маршалинг данных и два режима:
• Однократный режим (запрос-ответ);
• Режим мониторинга, постоянно получаем данные с периодом, определяемым механизмом обмена данными с целевым устройством;

Маршшалинг — процесс преобразования данных в формат, пригодный для хранения или передачи. Применяется когда информацию необходимо передать между различными частями одной программы или от одной программы к другой.

При однократном режиме пользователь нажимая кнопку в графическом функциональном объекте (виджете) генерирует сигнал, содержащий список параметров, данные которых следует считать в целевом устройстве (САУ) и передать в графический функциональный объект. Механизм обмена данными в основной программе обрабатывает сигнал и начинает запрашивать у САУ данные по RS-232, получаемые данные пакуются в QbyteArray и отправляются с сигналом в графический объект. Объект обладает списком запрашиваемых параметров и, следовательно, знает их типы, распаковывает данные, которые содержаться в QbyteArray и отображает их виде графиков и таблиц и специализированных графических виджетов (стрелочные индикаторы, цифровые индикаторы, кнопки с подсветкой и т.д.).

В режиме мониторинга, при инициализации плагина, система сразу запрашивает необходимый список параметров для плагина, и во время постоянного мониторинга своих параметров она считывает дополнительные параметры для плагина, и выдаёт их в виде пакета байт каждый цикл обмена данными. Период цикла обмена данными зависит от количества запрашиваемых параметров.

На данный момент проходит тестирование и одновременно разработка групп плагинов под разные задачи.

Был создан плагин шаблон который ускоряет процесс разработки новых плагинов. Используя плагин-шаблон для разработки нового функционального модуля необходимо создать новую графическую форму и реализовать алгоритмы обработки и визуализации данных.

Были разработаны программные модули-драйверы физического уровня для проводного интерфейса RS-232 и беспроводных WIFI и Bluetooth.

На сегодняшний день программный комплекс работает в 2-х канальном режиме, т. е. может работать одновременно с 2 САУ (это было требование заказчика). К любому из 2-х каналов пользователем подключаются плагины функциональных модулей.

При тестирование удалось одновременно запустить 12 плагинов которые успешно обрабатывались ядром. И даже 12 плагинов не являются пределом для данной системы. За счёт системы двойной буферизации Qt, время затрачиваемое на рисование плагинов уменьшается и предотвращает мерцания плагинов, поэтому при наращивания количества плагинов в дальнейшем основная нагрузка будет идти только на обмен данных по интерфейсу RS-232. Хотя практика показывает, что во время отладки, настройки, тестирования САУ двигателя достаточно 3-4 одновременно работающих плагина.

В результате работы получили программный комплекс для быстрой разработки технологических программ предназначенных для настройки, наладки и тестирования САУ для различных типов двигателей (мехатронных систем).

Были разработаны 2 комплекта плагинов для разных типов двигателя.

Подключая комплект плагинов для определенного типа САУ к программному комплексу получаем многофункциональную программу для настройки, наладки и тестирования этого типа САУ.



В дальнейшем планируется написание статьи по разработке собственных графических виджетов, под специфические задачи и отдельная статья по компоновке графических объектов.
Tags:
Hubs:
Total votes 17: ↑16 and ↓1+15
Comments39

Articles