Сборка OpenSCADA и прошивки для ARM-контроллеров фирмы ICP DAS (LP-5141)
	 | 
	
	 | 
		
		
		Имя: LP-5xxx
Основан: август 2011г
Завершен: сентябрь 2011г
Версия: 1.0.0
Участники: Роман Савоченко
Описание: Проект посвящён сборке OpenSCADA и прошивки для ARM контроллеров серии LP-5xxx и LP-8x{3|4}x фирмы ICP DAS.
Материалы: ftp.oscada.org/OpenSCADA/PLC/LP5xx1
		 Фирма 
ICP_DAS достаточно давно выпускает контроллеры на процессорах ARM архитектуры с предустановленным окружением ОС Linux, что делает интересным создание сборки OpenSCADA или новой прошивки с OpenSCADA.
 До последнего момента ряд причин препятствовали созданию сборки OpenSCADA для ARM-контроллеров ICP DAS:
-  отсутствие на руках одного из ARM-контроллеров; 
 -  неготовность OpenSCADA для работы на ARM-архитектуре; 
 -  крайне устаревшее окружение Linux ARM-контроллеров фирмы "ICP DAS".
 
 На данный момент все эти препятствия были устранены. Так, благодаря  Петру Литковцу на руках появился контроллер LP-5141, а к этому моменту  OpenSCADA в значительной степени была уже адаптирована к работе на  ARM-архитектуре, посредством отработки и стабилизации на наладонном  компьютере фирмы 
Nokia - 
N800.  В последствии же работы с контроллером LP-5141 было устранено последнее  препятствие путём обновления исходного программного окружения с  сохранением изначального функционала.
В общем, целью данного проекта является отработка механизмов и создание  сборки OpenSCADA для контроллеров семейства ARM фирмы "ICP DAS", а также  создание прошивок под контроллеры "ICP DAS", которые будут попадать в  руки разработчиков OpenSCADA.
1. ПЛК LP-5141
 ПЛК (рис.1) конструктивно выполнен в виде моноблока, который не содержит  встроенного УСО, кроме возможности установки одной специальной платы  расширения IO, а подключение внешнего осуществляется посредством  встроенного интерфейса RS-485, например, в виде модулей серии I-7000  фирмы "ICP DAS".

 Рис. ПЛК серии LP-5xxx.
 
 Процессор контроллера имеет следующие технические характеристики:
 CPU   |  PXA270 или совместимый (32-бит и 520МГц)   | 
  SDRAM   |  128 MB   | 
  Flash   |  64 MB   | 
  EEPROM   |  16 KB  Хранение данных: 40 лет; 1,000,000 циклов удаления/записи.   | 
  Расширенная Flash память   |  microSD сокет с одной microSD картой на 2GB (может поддерживать 16 GB microSDHC карты)   | 
  64-бит Серийный Номер Оборудования   |  Есть   | 
  Двойной Watchdog таймер   |  Есть   | 
  VGA   |  800 × 600   | 
  Ethernet порты   |  RJ-45 x 2, 10/100 Base-TX Ethernet Контроллер (Авто-согласование, авто MDI/MDI-X, LED индикатор)   | 
  USB 1.1 (хост)   |  1   | 
  COM1 (/dev/ttySA0)   |  RS-232 (RxD, TxD and GND); Не изолирован   | 
  COM2 (/dev/ttySA1)   |  RS-485 (D2+,D2-); 2500 VDC; изолирован   | 
  COM3 (/dev/ttySA3)   |  RS-232 (RxD, TxD and GND); Не изолирован   | 
  Рабочая температура   |  -25 ~ +75 °C   | 
2. Программное окружение на основе OpenSCADA.
 Программное окружение, основанное на ОС Linux, для ARM контроллеров  фирмы ICP DAS обычно имеет: ядро Linux 2.6.19, GLibC 2.2.5 и GCC 2.95.  Для сборки стороннего ПО фирмой ICP-DAS предоставляется SDK с  кросскомпилятором, набором библиотек и заголовков к ним (Linux  toolchain). Как можно видеть, версии GLibC и GCC очень старые, а именно  времён 2001 года. Сборка OpenSCADA в таком окружении фактически  невозможна. Если использование GLibC версии 2.2.5 ещё возможно, то GCC  версии 2.95 имеет C++ компилятор, который на сборке кода OpenSCADA  просто рушится, а стандартная библиотека C++ или STL крайне ограничена и  под неё требуется значительная и главное бессмысленная адаптация. По  этой причине потребовалось обновление исходного программного окружения  до версии GCC компилятора или библиотеки C++ не менее 3.
 Поскольку внутренняя флешь-память имеет сравнительно небольшой объём (64  Мб), а полная пересборка исходного программного окружения контроллера —  достаточно трудоёмкий процесс, то решено было обеспечить совместимость  базовых библиотек нового и старого окружения. А именно, возможность  использовать библиотеки вроде fontconfig, i8k из исходного окружения и  работу программ исходного окружения с новыми библиотеками.
 В процессе подбора нового программного окружения для процессора PXA-270  контроллера "ICP DAS" было опробовано несколько вариантов, поскольку  часть из них обладала теми или иными недостатками:
-  
crosstool-0.43  — интересный хотя и устаревший проект (последняя версия 2006 года) по  сборке Linux кроссокружения под нужное оборудование. Был отложен после  нескольких неудачных попыток собрать новое окружение для работы с  "Software FP" и "VFP". Как в последствии оказалось для объектных файлов  исходного окружения некорректно показывается информация о якобы наличии  там "Software FP" и "VFP", хотя на самом деле операции с вещественными  числами там осуществляются посредством "FPA". В последствии решения  проблемы, описанной в разделе "Замечания",  с помощью данного инструмента был собран ToolChain на основе профиля  "arm-xscale.dat" и "gcc-4.0.2-glibc-2.3.6-tls.dat", который в конечном  итоге был положен в основу новой прошивки.  -  
PXA-Linux Project — проект по созданию независимого набора инструментов Linux для сборки под процессор PXA. Имеет бинарную сборку 
02-25-2005/bin/arm-linux-toolchain-bin-12-15-04-driscoll.tar.gz.  Оказалось, что эта сборка собрана с "Software FP" и "VFP", а также  имеет проблемы в виде отключения ряда расширение компилятора gcc,  например: __attribute__((packed)).  -  
Voipac — бинарная сборка инструментов кросскомпиляции (
arm-linux-gcc-3.4.1.tar.gz)  от фирмы "Voipac" для собственного оборудования на процессоре PXA-270.  Данный набор подошёл идеально по всем параметрам и первоначально сборка  проводилась с помощью него. Данный ToolChain был собран с помощью ранее  рассмотренного 
crosstool. 
 Результирующее окружение контроллера с OpenSCADA было сформировано путём  замены базовых библиотек исходного окружения на библиотеки из нового  набора инструментов, сборки OpenSCADA и помещения файлов OpenSCADA в  дерево исходного окружения.
 OpenSCADA была собрана с отключением ряда библиотек и модулей. Так, были собраны и проверены модули и функции OpenSCADA:
-  Ядро OpenSCADA  — собрано с библиотекой LibGD2 (работа проверена). В процессе проверки и  адаптации расширены функции хранения конфигурации OpenSCADA в  конфигурационном файле. 
 -  DB.SQLite — БД SQLite (работа проверена). Собрана  библиотека и модуль OpenSCADA для работы с БД SQLite. В процессе  проверки обнаружена и выполнен обход ошибки в GLibC 2.3.2, связанной с  отсутствием проверки на взаимо-блокирование "rw"-ресурсов. 
 -  DB.DBF — БД DBF (работа проверена). Модуль работы с DBF-файлами версии 3. 
 -  Transport.Sockets — Модуль транспорта Сокетов TCP,  UDP и Unix (работа проверена). В процессе использования TCP-сокетов  обнаружена и устранена неинициализация структуры проверки состояния  сокета. 
 -  Transport.SSL — Модуль транспорта безопасных сокетов: SSL, TLS (работа проверена). 
 -  Transport.Serial — Модуль транспорта последовательных  интерфейсов (работа проверена). Выяснилось, что COM3 почему-то  расположен на устройстве /dev/ttySA3. 
 -  Protocol.SelfSystem — Модуль собственного протокола OpenSCADA (работа проверена). 
 -  Protocol.HTTP — Модуль реализации протокола HTTP (работа проверена). 
 -  Protocol.ModBus — Модуль реализации протокола ModBus (работа проверена). Конфигурация станции как сервера данных посредством протокола ModBus. 
 -  Protocol.OPC_UA — Модуль реализации протокола OPC UA  (работа проверена). Конфигурация станции как сервера данных посредством  протокола OPC UA. Обнаружена проблема различия представления  вещественного на x86 и ARM FPA! 
 -  Protocol.UserProtocol — Модуль свободной реализации простых протоколов пользователем посредством языка программирования OpenSCADA (работа проверена). 
 -  DAQ.System — Модуль данных операционной системы (работа проверена). Собран без использования библиотеки LibSensors. 
 -  DAQ.JavaLikeCalc — Модуль реализации Java-подобного пользовательского языка и вычислений на его основе (работа проверена). 
 -  DAQ.BlockCalc — Модуль реализации блочных вычислений (работа проверена). 
 -  DAQ.LogicLev — Модуль реализации источников данных логического уровня (работа проверена). 
 -  DAQ.ModBus — Модуль работы с источниками данных посредством протокола ModBus (работа проверена). 
 -  DAQ.DCON — Модуль работы с источниками данных  посредством протокола DCON (работа проверена). Например, с устройствами  ICP_DAS серии I-7000. Обнаружено и исправлено падение при получении  отрицательного размера ответа. Результат ответа возвращается теперь  всегда >= 0. 
 -  DAQ.ICP_DAS — Модуль источников данных ICP_DAS (нет оборудования для проверки).  Последовательные серии: I-87000 и I-7000; параллельные (быстрые): серии  I-8000. Модуль собран с библиотекой libi8k.a для ARM-архитектуры.
  -  DAQ.DAQGate — Модуль реализации шлюзования источников данных других станций OpenSCADA (работа проверена). 
 -  DAQ.OPC_UA — Модуль работы с источниками данных  посредством протокола OPC_UA (работа проверена). Обнаружена проблема  различия представления вещественного на x86 и ARM FPA - добавлено  преобразование при передаче! 
 -  DAQ.Siemens — Модуль работы с контроллерами Siemens, посредством Industrial Ethernet (ISO_TCP) (работа проверена). 
 -  DAQ.SNMP — Модуль сбора данных сетевого оборудования по протоколу SNMP (работа проверена). 
 -  Archive.DBArch — Модуль архивирования на БД (работа проверена). 
 -  Archive.FSArch — Модуль архивирования на файловую  систему (работа проверена). Обнаружена проблема при проверке архива,  выдача сообщения при запуске: "Error archive file structure:  <ARCHIVES/VAL/1s/CPULoad_load 2011-09-12 17:47:17.val>. Margin =  -8 byte. Will try fix it!". В результате выяснено, что алгоритм быстрого  подсчёта битов не выравнен на 4 байта при чтении буфера памяти -  исправлено. 
 -  UI.WebCfg — Модуль Web конфигуратора OpenSCADA (работа проверена). 
 -  UI.WebCfgD — Модуль Web динамического конфигуратора OpenSCADA (работа проверена). 
 -  UI.VCAEngine — Модуль движка визуализации (работа проверена). 
 -  UI.WebVision — Модуль визуализатора пользовательских интерфейсов в UI.VCAEngine посредством Web-интерфейса (работа проверена). 
 -  UI.WebUser — Модуль свободной пользовательской визуализации посредством Web-интерфейса (работа проверена). 
 -  Special.FLibComplex1 — Библиотека функций совместимости с Complex1(ООО НИП "ДІЯ") (работа проверена). Используются для блочного программирования. 
 -  Special.FLibMath — Библиотека стандартных математических функций (работа проверена). 
 -  Special.FLibSYS — Библиотека системных функций расширения OpenSCADA (работа проверена).
 
3. Замечания
 Поскольку выяснилось, что операции с вещественными числами выполняются  посредством команд сопроцессора FPA (Float Point Acceleration), которого  в данном процессоре просто нет, а вызовы самих команд осуществляются  через исключение имитацией в ядре Linux, то производительность  математических вычислений оказывается крайне низкой, даже в сравнении с  прямым "Software FP", "VFP". Например, вычисление одной операции sin(pi) осуществляется ~200 мкс, в сравнении с ~15 мкс на N800 с VFP и ~2 мкс на x86, детальнее в таблице по этой ссылке.  Таким образом, рассматривать данный контроллер как платформу для хоть  сколь-нибудь серьёзных вычислений нельзя! Мало того, вещественные числа  при работе с FPA хранятся по-другому, а именно - особый big-endian, что требует преобразования в случае с бинарным внешним обменом в типовое little-endian представление, например, для DAQ.OPC_UA.
 В исходной конфигурации порт COM1 (/dev/ttySA0) используется в роли  консоли, которая инициализируется командой ядра "console=/dev/ttySA0".  Однако, после настройки это не нужно, а часто и желательно освободить  ещё один COM-порт для других целей. Освободить COM1 от работы на консоль  можно переназначив другое устройство для этой роли, например, командой:  $ busybox setconsole /dev/tty1. Однако, этот способ не  полностью освобождает COM-порт и запросы теряются, вычитываясь  параллельным подключением. Вероятно нужно отредактировать параметры  строки запуска ядра в загрузчике U-Boot, хотя войти в него можно только в  положении RS=2, для которого однако параметры инициализации отделены от  основного режима работы RS=0. Нужно добиться входа в U-Boot от  основного режима работы RS=0!
 В процессе использования созданного программного окружения с OpenSCADA  обнаружена странная проблема, которая заключается в падении OpenSCADA  при доступе к экземпляру ресурсной строки из разных потоков. Проблема  воспроизводится при опросе контроллера по протоколу ModBus/RTU с  периодичностью 100мс, опросе отсутствующего модуля посредством DCON на  том же интерфейсе RS485, что и ModBus/RTU. В этот же момент  осуществляется периодическая (1 секунда) запись двух регистров в  опрашиваемый по протоколу ModBus/RTU контроллер. Падение происходит не  сразу, а в течение 10 минут - 5 часов. Разбор проблемы:
(*) В случае отключения записи в контроллер по протоколу ModBus/RTU падения не наблюдаются.
 (*) Выяснено, что падения начинают происходить в случае достижения  функции TMdContr::modBusReq() модуля DAQ.ModBus, а именно параллельного  доступа к свойству объекта контроллера "mPrt" в контексте конструктора  "XMLNode req(mPrt);" из разных потоков чтения и записи.
 (*) Для выяснения природы проблемы была настроена генерация  предсмертного дампа памяти, а также собран кроссовый отладчик gdb. При  изучении предсмертного дампа памяти выяснено, что происходит разрушение  стека и разумных причин в OpenSCADA для данного явления нет, а значит  это проблема системного окружения для специфических условий.
 (*) При доступе к свойству "mAddr" в первой строке функции  TMdContr::modBusReq() и проблемном контексте "XMLNode req(mPrt);" (при  неполной записи) падения не замечено.
 (*) Проверка вызова второй строки "XMLNode req(mPrt);" при записи и в  целом с постоянной "RTU". При замене на "RTU" в целом падение замечается  уже в другом месте. При замене только неполной записи падение не  замечается. Вторым и последним местом падения оказалась следующая строка  req.setAttr("id",id()). Общее между ними то, что  осуществляется доступ к элементу конфигурации строкового типа,  использующему объект ресурсного типа "ResString". Вывод: текущее  программное окружение некорректно работает с объектом "ResString" при  доступе на чтение (немодифицирующий) из двух разных потоков.
 (*) Способ хранения объекта "ResString" в элементе конфигурационного  поля "TCfg" значения не имеет, а именно — падение наблюдается при прямом  хранении "ResString" в "TCfg", а также при прямом обращении к объекту  "string" внутри "ResString" в случае с "id()".
 (*) Проверка при отключении охвата ресурсом проблемы не решает.
 (*) Сборка нового окружения с помощью "PTXDist" и запуск его через  "chroot": при запуске EABI окружения для TionPro270 из под chroot  происходит ошибка "Illegal instruction!". Не запускается EABI ядро от  TionPro270 c похожей ошибкой. Собранный ToolChain из профиля  "arm-xscale_hardfloat-linux-gnu_gcc-4.0.4_glibc-2.3.6_binutils-2.17_kernel-2.6.18.ptxconfig"  в "OSELAS.Toolchain-2011.11.0" падает с ошибкой сегментации при запуске  OpenSCADA, собранной под исходное окружение.
 (*) Сборка OpenSCADA с включением всех нужных модулей в библиотеку ядра OpenSCADA проблему также не решает.
 (*) Осуществлена проверка той же конфигурации на другом PXA270-устройстве (TionPro270)  для окончательного выяснения источника проблемы (аппаратного или  программного окружения) — конфигурация проработала беспроблемно двое  суток.
 (*) Заменить в объекте TCfg "ResString" на обычный "string" с выносом  ресурса доступа в объект контейнера TConfig, заодно и уменьшив  потребление памяти посредством обобщения ресурса доступа к объекту  строки, — замена осуществлена, проблема осталась.
 (*) Вычитать сборку с заменой "ResString" на обычный "string" в TCfg и проверить место текущего падения — место падения то же.
 (*) Взять "crosstool" и собрать несколько более свежий toolchain —  собран toolchain "gcc-4.0.2-glibc-2.3.6-arm-xscale-linux-gnu", проблема  воспроизводится, скорее всего проблема в работе с памятью текущего ядра.  В процессе изучения найдены прецеденты с подобными проблемами в  glibc-2.2 — 2.7, которые содержат реализацию malloc, небезопасную для  потоков (nothread-safe).
 (*) Замена аллокатора памяти — не удалось найти рабочей и при этом  прозрачной реализации стороннего аллокатора, ptmalloc3 просто падает.
 (*) Сборка ToolChain и OpenSCADA со всеми возможными параметрами  включения thread-safe — во всех вариантах проблема присутствует, а  именно на ToolChain с параметрами GLibC: "--with-tls --with-__thread" и OpenSCADA собрана с параметрами: "-pthread -D_REENTERANT".
 (*) Перехват обращений аллокации памяти и оборачивание глобальным ресурсом функций "С" malloc, free и "С++" new, delete   — падения наблюдаются.
 (+) Проверка гипотезы проблемности реализации (атомарности) COW (Copy on  Write) алгоритма в объекте "string" — копирование из объекта "string"  хранилища выполнено посредством val.c_str(), что  исключает выполнение COW: подтверждено, что данная проблема связана с  алгоритмом COW, а именно с атомарностью доступа к счётчику строк  "_Atomic_word _M_refcount;", вероятно, из-за устаревшей системы потоков  linuxthread.
4. Заключение
 В результате была получена сборка OpenSCADA для Linux контроллеров  ARM-архитектуры фирмы "ICP DAS". Сборку можно загрузить прямо на любой  Linux-ARM контроллер, распаковав её в корне работающей исходной системы.  При этом, однако, останутся дубликаты старых базовых библиотек  (/lib/*), которые после удачной перегрузки можно удалить.
 Для контроллеров семейства LP-5x4x создана прошивка со сборкой  OpenSCADA, которую можно загрузить стандартным для данных контроллеров  образом, который описан в фирменной документации "ICP DAS". Прошивка для  LP-5x4x возможно подойдёт и для LP-5x3x, однако это не проверялось!
 Ввиду устаревшей и неоптимальной исходной сборки Linux окружения от  "ICP_DAS", что накладывает ограничение на свободу сборки оптимального  окружения, по завершению проекта планируется обратиться к фирме  "ICP_DAS" с просьбой исправить данное положение дел.
(*) Обращение осуществлено однако никакой реакции, вплоть до ответа на запрос, не последовало!