В этой статье я сделал обзор одного из возможных подходов к созданию гибких и стабильных производственных систем уровня MES/industrial test platform ( c использованием набора измерительного и метрологического оборудования с различными протоколами связи) классической клиент-серверной архитектуры с использованием "чистого" SQL с программированием потоковых операций через легкий разработанный скриптовый язык. Старый добрый проверенный способ разработки в двухзвенной архитектуре здесь стал палочкой-выручалочкой, позволив сравнительно просто и относительно быстро командой из 2-х человек создать довольно сложную систему на базе разработанного для этого специального языка типа DSL. Конечно, это не язык в общем смысле универсальных языков, а табличный скриптовый язык, реализующий программу тестирования устройств с интерфейсом 4-20 мА HART с линейным и циклическим алгоритмом и поддержки косвенной адресации внутри цикла. Со своей специализированной задачей он справляется хорошо и дает возможность строить простые и сложные тесты "железа" из кубиков-операций, реализованных в клиентском ПО по программе, хранящейся в базе данных.
Постановка задачи
Необходимо было разработать программную систему для производства, поверки и тестирования интеллектуальных датчиков с протоколом HART на тестовых станциях с программируемым оборудованием. Кто не знает что такое HART - это протокол "точка-точка" частотной модуляции тока , который накладывается на токовую петлю 4-20 мА датчика и используется для калибровки,настройки и поверки интеллектуальных датчиков с токовой петлей 4-20 mA/HART. Производство таких изделий включает в себя линеаризацию передаточной характеристики сенсора, температурную калибровку токовой петли полиномами, поверку,различные тесты на этапах отработки и периодических испытаний с использованием циклов по давлению, температурам, напряжению питания и HART обмену. Необходимо иметь возможность редактировать функционал Тестов, то есть изменять программу тестирования без изменения кода приложения клиента и сервера. Естественно, нужно сохранять "сырые" данные тестирования и формировать протоколы тестирования, формировать логи и т п .
Одна тестовая станция должна была поддерживать несколько десятков датчиков и включать такое оборудование как компьютер, задатчик воздействий на датчики, климатическую камеру, измерительное оборудование (управляемый вольтметр 6.5 цифр), коммутатор каналов подключения датчиков, эталон (МЕРА) сопротивления, HART модем. Все приборы имеют различные интерфейсы управления, такие как USB, GPIB, TCP/IP, RS232. Тестовых станций в перспективе в будущем могло быть с десяток и больше. Отсюда была необходимость не только в системе управления различными процессами с датчиками, но и в некой системе для мониторинга процессов, которая бы показывала что происходит на каждой станции тестирования в режиме онлайн, текущие данные тестов, режимы работы оборудования, логи и т п.
Задача поначалу казалась очень непростой. Но какая бы ни была сложная система, стандартный подход к решению сложных задач состоит в их декомпозиции, разбивке сложной задачи на несколько более простых. Следуя этому принципу, можно выделить в данной системе несколько подсистем. Первая - это управление и работа с оборудованием и датчиками. Вторая - это программирование тестов и работа с базой данных. Третья- это обработка данных и расчеты, формирование протоколов. Четвертая - мониторинг тестирования. Такое структурирование уже проясняет архитектуру требующейся программной системы и можно рассматривать различные варианты создания подсистем.
Работа с оборудованием и датчиками
Первый вариант, который пришел в голову - использовать какой либо универсальный язык с ООП, описать на нем структуру команд всех интерфейсов приборов и т п. Вариант был сразу отметен ввиду сложности и длительности процесса такой разработки на универсальном языке типа С# и других. Тот же С# , к примеру, плохо подходит для создания предметных сущностей для работы с оборудованием. Я видел такие подходы в компании где работал до этого и в общем, это как-то работало, но требовало создания кучи дополнительных абстактных сущностей и классов в программе. У меня не было ни команды, ни возможности и времени для подобного подхода к разработке. А сейчас тенденции в мире измерений и тестирования электроники такие, что ведущие компании по производству интеллектуальных приборов переходят (или уже перешли) в таких задачах на оборудование и программную систему LabView компании National Instruments (теперь это ЭМЕРСОН). Все необходимые интерфейсы к приборам и оборудованию в системе LabView есть и использовать их относительно просто (тому кто знаком с языком управления приборами SCPI, к примеру). Оставалось найти программиста LabView. Их не очень много, так как графическая среда разработки в которой вообще нет кода, довольно специфична. Такой человек в команду нашелся и довольно хорошей квалификации в этой области программирования.
Сразу было понятно, что если в качестве клиентской части применять LabView на тестовой станции, то использовать ООП не получится, так как эта система его не поддерживает. Вообще любой ЯП в парадигме создания ПО с применением ООП страдает не только излишней нагруженностью абстракциями, но и потребностью в сложном тестировании относительно несложных вещей, сопровождающихся усложненим и запутанностью логики предметных аспектов. У нас не было таких возможностей. Поэтому архитектурные варианты с бизнес-логикой на клиенте сразу были исключены из рассмотрения. Тот кто видел программы на Labview, тот сразу поймет , что усложнять и без того сложные диаграммы LabView можно, но не нужно, мы бы погрязли в болоте взимозависимостей бизнес-логики очень надолго. Вся логика тестирования ( а это потоки операций) должна быть вынесена наружу, в программу или в скрипт теста. Сам скрипт может храниться в файле или таблице базы данных. После некоторых раздумий было принято решение хранить скрипт теста в таблице базы данных, так как вся обработка данных (или почти вся, за исключением расчета коэффициентов регресии ) в этой архитектуре тоже должна быть в базе данных.
Программирование тестов и работа с базой данных
Идея с редактируемым скриптом теста сразу натолкнула на мысль, что клиент LabView тестовой станции должен быть по сути интерпретатором, выполняющим команды из скрипта теста. Здесь не требовалалась скорость работы, так как операции были довольно длительные. Фактически это означало, что надо разработать некую систему команд в виде табличного скрипта, которая будет включать работу с оборудованием, базой данных, климатической камерой, датчиками и Тест в данном случае будет состоять из таблицы строк команд с параметрами в виде линейного алгоритма, соответствующий определенному функционалу Теста, который будет выполнятся на тестовой станции клиентом LabView в режиме интерпретатора. Функционал Теста как поток тогда можно строить из "кирпичиков" - операций Теста.
Оставалась одна сложность - как разбивать Tесты на операции ( команды) по функционалу. Видов тестов требовалось довольно много. Если разбить мелко - будет слишком длинные тесты в табличном виде и редактировать их будет неудобно. Если разбить крупно - снижается гибкость программирования теста. Золотая середина была найдена так - первый вариант основного теста температурной калибровки датчика делался с жесткой логикой на клиенте Labview в виде линейного алгоритма потока операций. Это помогло понять подходы к разбиению теста на операции. Далее все вылилось в создание специфического для данной области табличного скрипта ( DSL ) , на котором можно было составлять программы тестирования. Сначала был реализован линейный алгоритм выполнения операций, но еще и хотелось использовать циклы для уменьшения количества строк программы теста. Обычно циклы делаются в клиентском приложении. Но в этой задаче я решил сделать наоборот и циклы были сделаны в БД. Задача была решена очень просто добавлением нескольких таблиц и доработкой одной хранимой процедуры. Но чтобы до этого дойти пришлось немного поразмышлять и поэкспериментировать с кодом SQL. Эксперименты показали что все работает и циклы можно применить в хранимых процедурах и хранить параметры циклов таблицах. Это было правильное решение, как оказалось в дальнейшем, котороеувеличило выживаемость системы при аварийном отключении питания.
Исходя из этого в систему команд табличных скриптов тестов были добавлены команды инициализации цикла и проверки окончания цикла. Также реализованы были операции с таймерами, инициализация циклов по видам воздействий. Всего видов циклов по воздействиям было сделано 3 плюс общий цикл. Реализация общего цикла была сделана в базе данных в отдельной таблице, в которую записывались параметры цикла ( начальное значение переменной цикла, конечное значение переменной цикла, текущее значение, активный тестируемый пул датчиков, станция тестирования). Это все делалось при выполнении операции инициализации цикла типа WHILE. Также был создана специальная операция цикла по длительности настройки привязанного к ней таймера, внутри которого крутились операции в течение времени настройки таймера. Введение оператора цикла и таймера позволило резко сократить ( почти в два раза ) количество строк Теста и увеличить гибкость программирования.
Перед выполнением цикла выполнялись операции загрузки на клиентское ПО статических моделей воздействий из таблиц БД, таких как наборы температур и наборы давлений в виде процентов шкалы прибора для клиенткой логики перехода по температурам и давлениям. Для более гибкого программирования из самого скрипта были добавлены операции для программой логики из скрипта теста ( в зависмости от вида воздействия) и потребовалась дополнительная таблица циклов по давлениям, температурам и напряжению питания с указанием начальных и конечных значений величин воздействий, шага воздействия и способа модификации переменной цикла до или после начала цикла ( ++i и i++ по аналогии с циклами в С++).

При этом был вопрос - сколько нужно параметров для операций (команд), которые будут использоваться в скрипте теста? Не хотелось использовать много , так как это усложняло программирование теста. Архитектура таблиц циклов была сделана так, что всего 2 параметра было достаточно для всех созданных операций в скриптах ( всего было разработано больше 100 операций, из которых можно строить программы тестирования датчиков). Некоторые операции внутри цикла в зависимости от параметров были сделаны в двух ипостасях- как зависимые от номера цикла если привязывались к циклу , так и независимые от номера цикла и также могли использоваться внутри цикла таймера и там зацикливаться на себя. То есть можно крутить наборы операций внутри таймера, пока он работает и после прекращения работы таймера управление перейходит на следующую строку/операцию программы тестирования.
Сначала все тесты программировались в хранимой процедуре в виде текста заполнения таблицы. Это было не очень удобно, так как приходилось лезть в серверный код и в редакторе процедуры править программу. Позже был разработан табличный редактор Теста в отдельной программе. Он позволял копировать Тесты , редактировать и "компилировать" их ( стирать старый тест и заменять его новым). Так как операций и вариантов 2-х параметров было разработано много, то запомнить их было сложно. Была добавлена интерактивная помощь при разработке теста. При выборе строки Теста показывалось описание параметров. Получилось довольно не затратно - программист Теста заботится только о порядке операций, добавлении или удалении операций и значениях 2-х параметров. Все остальное ( расстановка нумерации строк, ссылок на следующую команду теста, комментарии к операциям с учетом циклов и т п) взяла на себя система SQL на сервере ( используется встроенная хранимая процедура корректировки указанного Теста, которая автоматически формирует тест и все ссылки в таблицах теста). Доступно и копирование тестов. Новый Тест можно делать не с нуля, а скопировать похожий и отредактировать. Всего сейчас сделано более 100 программ тестирования, которые используются как для производства, так и для тестирования приборов с интерфейсом 4-20мА\HART.
Работа с базой данных и формирование протокола тестирования
Клиент Labview работает с базой данных и датчиками через программу теста в режиме интерпретатора. Программа может включать множество операций. Операции разработаны разные, и контрольные и расчетные , вплоть до транспонирования матриц в SQL для расчета коэффициентов полиномов, применяемых для линеаризации передаточной характеристики и компенсации температурной погрешности метрологических параметров датчиков. Использование расчета коэффициентов полиномов в БД я посчитал слишком затратным и сложным lдля реализации на сервере SQL. Поэтому для этого был использован готовый компонент расчета коэффициентов на клиенте labview, которому скармливали подготовленные матрицы данных с сервера, выбрав в компоненте метод расчета, дающий наибольшую точность обратным расчетом с испльзованием полученных коэффициентов.
Работа клиентской части в качестве интерпретатора происходит следующим образом. Считывание строки скрипта из программы и выполнение операции происходит построчно из таблицы скрипта вместо загрузки его полностью. Табличный скрипт представляет собой односвязный список, где каждая строка связывается со следующей с помощью ссылки на новую строку в таблице Теста.
Такой режим построчной загрузки был выбран для того, чтобы был доступен режим корректировки Теста в процессе его выполнения, подобно тому, как запускается любая программа в режиме отладки. Скрипт теста связывает строки по ссылке, но она скрыта от пользователя и формируется автоматически при "компиляции" табличного теста после его создания. Ссылка на следующую команду в операции проверки конца цикла указывает на следующую строку программы Теста и когда переменная цикла достигает указанное количество циклов, программа переходит на следующую строку после операции проверки конца цикла. Все эти простые "хитрости" cо скриптами и циклами, были реализованы в хранимой процедуре, которая проходя по таблице теста автоматически формировала связный список, делала автоматическую расстановку ссылок на операции, циклы и таймеры. В итоге получилось реализовать неограниченную вложенность циклов ( хотя это и не нужно было), режим пошагового выполнения программы Теста для отладки операций, остановка выполнения операций , ручной переход на любую строку программы вперед и назад. Практика показала что это очень удобно при отладке теста и важно при различных нестандартных ситуациях в процессе тестирования, когда нужно повторить ранее выполненные операции , пропустить операции и даже добавить операцию в выполняемый Тест и т д. Циклы в БД помогли и в том, что при внезапных отключениях питания тестовых станций благодаря хранению данных циклов на сервере стал возможен режим перезапуска теста без повторения уже выполненных операций. Так как основная информация, данные программы и параметры длительных циклов хранятся в SQL базе данных, а не на клиенте и соединение с ней не обрывается, так как БД защищена от пропадания питания, то режим перезапуска позволяет не запускать тест заново, а вернуться при перезапуске в ту же точку где программа теста была остановлена. Что касается настройки адресов HART датчиков, то для перезапуска теста и экономии времени все адреса также сохранялись в БД в начале теста и при перезапуске теста они автоматически восстанавливались специальной процедурой.

Глядя на программу, кажется что все это надо писать руками, но на самом деле нужно только менять три параметра - номер операции, параметр операции и признак цикла. Режим интерактивной помощи позволяет при добавлении операции или ее корректировке и просмотре программы сразу показывать параметры операций и их описание. После того как программа Теста составлена , достаточно ее "скомпилировать" ( запустить операцию, которая автоматичеки ее упакует в таблицу и сама напишет комментарии), чтобы использовать для работы или отладки. Как и в любом языке, при составлении программмы Теста надо учитывать порядок выполнения операций исходя из логики Теста. Пошаговый режим работы на клиенте позволяет отладить работу программы даже в режиме активного тестирования.
Мониторинг тестовых станций
Сбор данных оборудования для мониторинга тестовых станций делает клиент Labview, который сохраняет их в БД c интервалом 2 сек для каждой станции и ведет лог операций. Для исключения взаимоблокировок у каждой станции тестирования есть своя таблица данных мониторинга оборудования. Первоначальный вариант содержал общую таблицу данных, но в дальнешем , при масштабировании системы таблица данных состояния станций была разделена на отдельные таблицы для исключения взаимоблокировок. Анализ взаимоблокировок показывал, что они периодически возникали в мониторинге и не то чтобы сильно мешали, так как сервер автоматически разруливал ситуацию, но в связи с масшабированием системы желательно было их устранить. Новые таблицы данных всех станций были объединены представлением (view) и данные в них записывались через триггер INSTEAD OF для представления. Я вообще редко использую триггера. Но зна этом этапе он был использован для быстрого прототипирования. В дальнейшем триггер был убран и сделана реализация через динамический SQL , что упростило серверный код и оптимизировала скорость работы мониторинга.
Лог всех выполненных операций сохранялся в БД. Лог операций для оптимизации мониторинга , на котором он был основан, был разделен на оперативный и архивный. Такое разделение необходимо было сделать для системы онлайн мониторинга выполняемых тестов для минимизации времени выполнения хранимых процедур мониторинга. Каждая процедура мониторинга была оптимизирована с учетом плана выполнения хранимой процедуры, создания нужных индексов и быстрых функций (ITVF), возвращающих наборы данных. Мониторинг выполняемых тестов в онлайн использует только оперативный лог, который через триггер дублируется в архивный. Оперативный лог каждой станции при запуске нового теста сначала очищается. Вся история тестов далее хранится в архивном логе. Под систему мониторинга было сделано отдельное приложение, которое используя данные оборудования и логи операций формирует и показывает следующие указанные на рисунке ниже дашборды и представления в режиме on-line c интервалом 1,6 сек. Кроме того, для всей экосистемы программ на SQL ( не только стенды , есть еще несколько приложений , использующих сервер SQL) добавлен просмотр запущенных приложений SQL, логи пользователей приложений, историю всех изменений DDL на сервере включая индексы, функции, и хранимые процедуры.
В итоге при работе мониторинга влияние его пренебрежимо мало ( общая загрузка ЦП не более 4 - 5% при одновременной работе 8 станций) и взаимоблокировки ресурсов сервера полностью отсутствуют. Ниже для примера показан краткий перечень основных возможностей отображения и контроля параметров тестирования. Что можно получить в режиме онлайн:

тесты и операции, выполненные и выполняемые в реальном времени на каждой станции тестирования
статусы и текущие параметры оборудования выбранной тестовой станции.
Полный контроль прохождения теста с удаленного компьютера.
История прохождения теста и данные тестирования в онлайн режиме с показом метрологических данных в виде таблицы и графика.
Выгрузка данных в csv.
Бегущая строка статусов тестовых станций и датчиков в онлайн.
Статус логов бэкапа и переноса логов системы в архив и т п.
Эта система позволяет мониторить все логи других приложений SQL (а их за это время набралось четыре сложных приложения и нужен контроль логов) и поддерживает просмотр истории SQL кода на сервере ( процедуры и пр.)
Здесь я применил бегущую строку для онлайн-тестов. Нестандартное решение, но в общем работает, экономит место на экране значительно и показывает статусы и операции, ошибки в данных и т п. При верификации датчиков показывает стандартный метрологический график в виде "бабочки', облегчая оператору восприятие данных не только в виде таблиц с цифрами, но и в удобном графическом виде для оценки прохождения теста.
Система отличается высокой стабильностью и предсказуемостью. Нестандартные ситуации с получением данных обрабатываются в базе данных и в случае ошибок программа уходит в режим паузы для выбора дальнейших действий оператором Теста. Нестандартные ситуации с приборами и задатчиками обрабатываются на клиенте LabView. Все такие ситуации отображаются в операционном логе и в программе мониторинга станций тестирования.
Сложно в небольшой статье описать все что удалось реализовать в связке SQL + LabView с использованием разработанного скиптового языка (DSL) и функционального подхода к программированию потоковых операций. Эта связка показала , что при использовании скриптового DSL в БД можно относительно быстро и просто реализовать сложные тесты сбора и обработки данных с интеллектуальных приборов без усложнения клиентского приложения.
PS.
Система начиналась с одного стенда и сейчас увеличилась и насчитывает больше 10 станций тестирования. Не было каких то особых проблем в ПО с бизнес-логикой в хранимых процедурах при масштабировании системы в несколько раз. Как я описал выше, для исключения редких взаимоблокировок была изменена только архитектура части системы поддержки мониторинга, проверены и оптимизированы функции и процедуры, планы хранимых процедур и индексы на предмет минимизации загрузки ЦП.
