# ParamTemplLibs

ID: tests
NAME: Tests
DB: tmplib_tests
DESCR:
Templates library of the test parameters for PLC series S7 of the firm Siemens.

Author: Roman Savochenko <roman@oscada.org>

uk#DESCR:
Бібліотека шаблонів параметрів для контролерів фірми Siemens серії S7.

Автор: Роман Савоченко <roman@oscada.org>

ru#DESCR:
Библиотека шаблонов параметров для контроллеров фирмы Siemens серии S7.

Автор: Роман Савоченко <roman@oscada.org>


ID: base
NAME: Main library
uk#NAME: Основна бібліотека
DB: tmplib_base
ru#NAME: Основная библиотека
DESCR:
Library of the main templates of the DAQ-sources processing and related services.

The library was created to provide main templates of the DAQ-sources processing and related services.

Author: Roman Savochenko <roman@oscada.org>
Used by: Most projects on OpenSCADA
Founded: January 2006
Version: 2.0.0
License: GPLv2
DOC: Libs_Main|Libs/Main

uk#DESCR:
Бібліотека основних шаблонів опрацювання DAQ-джерел та похідних сервісів.

Бібліотеку створено для надання основних шаблонів опрацювання DAQ-джерел та похідних сервісів.

Автор: Роман Савоченко <roman@oscada.org>
Використано: Більшість проектів OpenSCADA
Засновано: Січень 2006
Версія: 2.0.0
Ліцензія: GPLv2
DOC: Libs_Main|Libs/Main

ru#DESCR:
Библиотека основных шаблонов обработки DAQ-источников и производных сервисов.

Библиотека создана для предоставления основных шаблонов обработки DAQ-источников и производных сервисов.

Автор: Роман Савоченко <roman@oscada.org>
Использовано: Большинство проектов OpenSCADA
Основано: Январь 2006
Версия: 2.0.0
Лицензия: GPLv2
DOC: Libs_Main|Libs/Main


ID: DevLib
NAME: Industrial devices
uk#NAME: Промислові пристрої
DB: tmplib_DevLib
ru#NAME: Промышленные устройства
DESCR:
The user protocol devices library created to provide access to industrial device's data through network, like to common industrial automation devices and wide resources counters, with protocols simple enough to implement into the User Protocol module, using the presented complex protocols (ModBus, OPC_UA, HTTP) or directly on the internal like to Java language.

The template's names and their parameters are available in languages: English, Ukrainian and Russian. Their source code wrote in the human-language independent mode with calls for the translations by the function tr() and the message's translation also allowed for English, Ukrainian and Russian.

Author: Roman Savochenko <roman@oscada.org>, Constantine (IrmIngeneer) (2018), Arsen Zakojan (2017), Ruslan Yarmoliuk (2017)
Founded: January 2010
Version: 2.6.1
License: GPLv2
DOC: Libs_Devices|Libs/Devices

uk#DESCR:
Бібліотеку пристроїв користувацьких протоколів створено для надання доступу до даних промислових пристроїв через мережу із доволі простим протоколом, на кшталт пристроїв загальної промислової автоматики та лічильників різних ресурсів, із протоколом достатньо простим до реалізації у модулі користувацького протоколу, з використанням наявних комплексних протоколів (ModBus, OPC_UA, HTTP) або безпосередньо на внутрішній мові подібній до Java.

Автор: Роман Савоченко <roman@oscada.org>, Константин (IrmIngeneer) (2018), Арсен Закоян (2017), Руслан Ярмолюк (2017)
Засновано: Січень 2010
Версія: 2.6.1
Ліцензія: GPLv2
DOC: Libs_Devices|Libs/Devices


ID: PrescrTempl
NAME: Prescriptions
uk#NAME: Рецепти
DB: tmplib_PrescrTempl
ru#NAME: Рецепты
DESCR:
The library is created to provide an environment of execution of scenarios of the technological operations — prescriptions, and frames of the user interface about them, including the frame of creation/edition the prescriptions and two frames of the execution control and reporting — "Prescription — run" and "Prescription — run, simple". The library is built on the basis primitives of the widgets and the internal programming language JavaLikeCalc, including templates and commands.

The section contains DAQ-templates of the prescription manager and commands of the "command-template" mode, which are intended to be connected to the logic level controller, by creating related parameters of the prescription manager and commands, which available for the user to choose from, and which will carry out all the work with the prescriptions-programs for their processing and execution.

The element's names and their parameters are available in languages: English, Ukrainian and Russian. Their source code wrote in human-language independent mode with calls for the translations by the function tr() and the message's translation also allowed for English, Ukrainian and Russian.

Author: Roman Savochenko <roman@oscada.org>
Sponsored by: Vassily Grigoriev, the Laboratory of Vacuum Technologies
Sponsored by, about the controller templateization: Magomed, SAVTECH
Founded: April 2012
Version: 1.1.0
License: GPLv2
DOC: Libs_Prescriptions|Libs/Prescriptions

uk#DESCR:
Бібліотека створюється для надання середовища виконання сценаріїв технологічних процесів — рецептів, та кадрів користувацького інтерфейсу довкола нього, включно з кадром створення/редагування рецептів та двома кадрами контролю виконання та звітності — "Рецепт — виконання" та "Рецепт — виконання, простий". Будується бібліотека на основі примітивів віджетів та мови внутрішнього програмування JavaLikeCalc, включно для шаблонів та команд.

Розділ містить DAQ-шаблони менеджеру рецептів та команд режиму "команда-шаблон", які призначено до підключення у контролері логічного рівня, через створення відповідно параметрів менеджеру рецептів та команд, доступних до обрання користувачем, які і здійснюватимуть там всю роботу із рецептами-програмами щодо їх опрацювання та виконання.

Назви елементів та їх параметрів доступні на мовах: Англійська, Українська та Російська. Їх вихідний код написано у мово(людська)-незалежному режимі з викликом функції перекладу tr() та переклад цих повідомлень також доступний Англійською, Українською та Російською.

Автор: Роман Савоченко <roman@oscada.org>
Спонсоровано: Василь Григор'єв, Лабораторія Вакуумних Технологій
Спонсоровано, щодо шаблонізації контролеру: Магомед, SAVTECH
Засновано: Квітень 2012
Версія: 1.1.0
Ліцензія: GPLv2
DOC: Libs_Prescriptions|Libs/Prescriptions

ru#DESCR:
Библиотека создаётся для предоставления среды исполнения сценариев технологических процессов — рецептов, и кадров пользовательского интерфейса около него, включая кадр создания/редактирования рецептов и два кадра контроля исполнения и отчётности — "Рецепт — исполнение" и "Рецепт — исполнение, простой". Строится библиотека на основе примитивов виджетов и языка внутреннего программирования JavaLikeCalc, включая для шаблонов и команд.

Раздел содержит DAQ-шаблоны менеджера рецептов и команд режима "команда-шаблон", которые предназначены к подключению в контроллере логического уровня, путём создания соответственно параметров менеджера рецептов и команд, доступных для выбора пользователем, которые и будут осуществлять там всю роботу с рецептами-програмами на предмет их обработки и исполнения.

Названия элементов и их параметров доступны на языках: Английский, Украинский и Российский. Их исходный код написан в языко(человеческий)-независимом режиме с вызовом функции перевода tr() и перевод этих сообщений также доступен Английским, Украинским и Российским.

Автор: Роман Савоченко <roman@oscada.org>
Спонсировано: Василий Григорьев, Лаборатория Вакуумных Технологий
Спонсировано, на предмет шаблонизации контроллера: Магомед, SAVTECH
Основано: Апрель 2012
Версия: 1.1.0
Лицензия: GPLv2
DOC: Libs_Prescriptions|Libs/Prescriptions


ID: LowDevLib
NAME: Low-level devices
uk#NAME: Низькорівневі пристрої
DB: tmplib_LowDevLib
ru#NAME: Низкоуровневые устройства
DESCR:
Library of templates to provide access to device's data of the low-level buses.

The user protocol devices library created to provide access to device's data of low-level buses, with protocols simple enough to implement into the User Protocol module or directly on the internal like to Java language.

The template's names and their parameters are available in languages: English, Ukrainian and Russian. Their source code wrote in the human-language independent mode with calls for the translations by the function tr() and the message's translation also allowed for English, Ukrainian and Russian.

Author: Roman Savochenko <roman@oscada.org>, Arcadiy Kisel (2017)
Founded: Jul 2016
Version: 1.4.0
License: GPLv2
DOC: Libs_LowLevelDevices|Libs/LowLevelDevices

uk#DESCR:
Бібліотека шаблонів надання доступу до даних пристроїв низькорівневих шин.

Бібліотеку пристроїв користувацьких протоколів створено для надання доступу до даних пристроїв низькорівневих шин, із протоколом достатньо простим до реалізації у модулі користувацького протоколу або безпосередньо на внутрішній мові подібній до Java.

Назви елементів та їх параметрів доступні на мовах: Англійська, Українська та Російська. Їх вихідний код написано у мово(людська)-незалежному режимі з викликом функції перекладу tr() та переклад цих повідомлень також доступний Англійською, Українською та Російською.

Автор: Роман Савоченко <roman@oscada.org>, Аркадій Кисіль (2017)
Засновано: Липень 2016
Версія: 1.4.0
Ліцензія: GPLv2
DOC: Libs_LowLevelDevices|Libs/LowLevelDevices

ru#DESCR:
Библиотека шаблонов предоставления доступа к данным устройств низкоуровневых шин.

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

Названия элементов и их параметров доступны на языках: Английский, Украинский и Российский. Их исходный код написан в языко(человеческий)-независимом режиме с вызовом функции перевода tr() и перевод этих сообщений также доступен Английским, Украинским и Российским.

Автор: Роман Савоченко <roman@oscada.org>, Аркадий Кысиль (2017)
Основано: Июль 2016
Версия: 1.4.0
Лицензия: GPLv2
DOC: Libs_LowLevelDevices|Libs/LowLevelDevices


# UserFuncLibs

ID: techApp
NAME: Technological apparatuses
DB: techApp
uk#NAME: Технологічні апарати
ru#NAME: Технологические аппараты
DESCR:
Library of models of the technological apparatuses for creating complex simulators of the technological processes of block-schemes of the module DAQ.BlockCalc.

The library is created to provide models of devices of the technological processes. The library is not static, but based on the module JavaLikeCalc, allowing to create calculations on the Java-like language.

To address the library functions you can use the static call address DAQ.JavaLikeCalc.lib_techApp.{Func}() or dynamic SYS.DAQ.JavaLikeCalc["lib_techApp"]["{Func}"].call(), SYS.DAQ.JavaLikeCalc["lib_techApp"].{Func}()". Where {Func} — function identifier in the library.

Author: Roman Savochenko <roman@oscada.org>, Maxim Lysenko (2007,2010), Ksenia Yashina (2007)
Founded: October 2005
Sponsored by: DIYA Ltd
Version: 2.0.1
License: GPLv2
DOC: Libs_Technological_apparatuses|Libs/Technological_apparatuses

uk#DESCR:
Бібліотека моделей технологічних апаратів для створення комплексних моделей технологічних процесів, блокових схем модуля DAQ.BlockCalc.

Бібліотека створюється для надання моделей апаратів технологічних процесів. Бібліотека не є статичною, а будується на основі модуля JavaLikeCalc, який дозволяє створювати обчислення на мові схожій на Java.

Для адресації до функцій цієї бібліотеки можна використати статичну адресу виклику DAQ.JavaLikeCalc.lib_techApp.{Func}() або динамічну SYS.DAQ.JavaLikeCalc["lib_techApp"]["{Func}"].call(), SYS.DAQ.JavaLikeCalc["lib_techApp"].{Func}(). Де {Func} — ідентифікатор функції у бібліотеці.

Автор: Роман Савоченко <roman@oscada.org>, Максим Лисенко (2007,2010), Ксенія Яшина (2007)
Засновано: Жовтень 2005
Спонсоровано: ТОВ "ДІЯ"
Версія: 2.0.1
Ліцензія: GPLv2
DOC: Libs_Technological_apparatuses|Libs/Technological_apparatuses

ru#DESCR:
Библиотека моделей технологических аппаратов для создания комплексных моделей технологических процессов, блочных схем модуля DAQ.BlockCalc.

Библиотека создаётся для предоставления моделей аппаратов технологических процессов. Библиотека не является статической, а строится на основе модуля JavaLikeCalc, позволяющего создавать вычисления на Java-подобном языке.

Для адресации к функции этой библиотеки можно использовать статический адрес вызова DAQ.JavaLikeCalc.lib_techApp.{Func}() или динамический SYS.DAQ.JavaLikeCalc["lib_techApp"]["{Func}"].call(), SYS.DAQ.JavaLikeCalc["lib_techApp"].{Func}(). Где {Func} — идентификатор функции в библиотеке.

Автор: Роман Савоченко <roman@oscada.org>, Максим Лысенко (2007,2010), Ксения Яшина (2007)
Основано: Октябрь 2005
Спонсировано: ООО "ДІЯ"
Версия: 2.0.1
Лицензия: GPLv2
DOC: Libs_Technological_apparatuses|Libs/Technological_apparatuses


ID: servProc
NAME: Service procedures
DB: lib_servProc
uk#NAME: Сервісні процедури
ru#NAME: Сервисные процедуры
DESCR:
Library of the service procedures of different application.

The library is created to provide service functions of performing service tasks about the OpenSCADA environment. The library is not static, but based on the module JavaLikeCalc, allowing to create calculations on the Java-like language. The functions' names and their parameters are available in languages: English, Ukrainian and Russian.

To addressing the library functions you can use the static call address DAQ.JavaLikeCalc.lib_servProc.{Func}() or dynamic SYS.DAQ.JavaLikeCalc["lib_servProc"]["{Func}"].call(), SYS.DAQ.JavaLikeCalc["lib_servProc"].{Func}()". Where {Func} — function identifier in the library.

Author: Roman Savochenko <roman@oscada.org>
Founded: November 2017
Version: 1.2.1
License: GPLv2
DOC: Libs_Service_procedures|Libs/Service_procedures

uk#DESCR:
Бібліотека сервісних процедур різноманітного застосування.

Бібліотека створюється для надання сервісних функцій виконання службових завдань довкола оточення OpenSCADA. Бібліотека не є статичною, а будується на основі модуля JavaLikeCalc, який дозволяє створювати обчислення на мові схожій на Java. Назви функцій та їх параметрів доступні на мовах: Англійська, Українська та Російська.

Для адресації до функцій цієї бібліотеки можна використати статичну адресу виклику DAQ.JavaLikeCalc.lib_servProc.{Func}() або динамічну SYS.DAQ.JavaLikeCalc["lib_servProc"]["{Func}"].call(), SYS.DAQ.JavaLikeCalc["lib_servProc"].{Func}(). Де {Func} — ідентифікатор функції у бібліотеці.

Автор: Роман Савоченко <roman@oscada.org>
Засновано: Листопад 2017
Версія: 1.2.1
Ліцензія: GPLv2
DOC: Libs_Service_procedures|Libs/Service_procedures

ru#DESCR:
Библиотека сервисных процедур различного применения.

Библиотека создаётся для предоставления сервисных функций исполнения служебных задач около окружения OpenSCADA. Библиотека не является статической, а строится на основе модуля JavaLikeCalc, позволяющего создавать вычисления на Java-подобном языке. Названия функций и их параметров доступны на языках: Английский, Украинский и Российский.

Для адресации к функции этой библиотеки можно использовать статический адрес вызова DAQ.JavaLikeCalc.lib_servProc.{Func}() или динамический SYS.DAQ.JavaLikeCalc["lib_servProc"]["{Func}"].call(), SYS.DAQ.JavaLikeCalc["lib_servProc"].{Func}(). Где {Func} — идентификатор функции в библиотеке.

Автор: Роман Савоченко <roman@oscada.org>
Основано: Ноябрь 2017
Версия: 1.2.1
Лицензия: GPLv2
DOC: Libs_Service_procedures|Libs/Service_procedures


ID: doc
NAME: Reports' and documents' library
DB: flb_doc
uk#NAME: Бібліотека звітів та документів
ru#NAME: Библиотека отчётов и документов
DESCR:
Provides the combined library of the reports, documents and related functions of common and the industrial automation.

The service functions of the frames of reports and documents are intended to perform the characteristic tasks of obtaining reporting data, for which you need to perform some verification or counting, for example, to check the validity and to summarize. Forming complex data, such as charts embedded in a document, can also be a service function.

To address the library functions you can use the static call address DAQ.JavaLikeCalc.lib_doc.{Func}() or dynamic SYS.DAQ.JavaLikeCalc["lib_doc"]["{Func}"].call(), SYS.DAQ.JavaLikeCalc["lib_doc"].{Func}()". Where {Func} — function identifier in the library.

The element's names and their parameters are available in languages: English, Ukrainian and Russian. Their source code wrote in human-language independent mode with calls for the translations by the function tr() and the message's translation also allowed for English, Ukrainian and Russian.

Founded: January 2008
Author: Roman Savochenko <roman@oscada.org>
Version: 2.0.3
License: GPLv2
DOC: Libs_Documents|Libs/Documents

uk#DESCR:
Надає комбіновану бібліотеку звітів, документів та пов'язаних функцій загальної та промислової автоматизації.

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

Для адресації до функцій цієї бібліотеки можна використати статичну адресу виклику DAQ.JavaLikeCalc.lib_doc.{Func}() або динамічну SYS.DAQ.JavaLikeCalc["lib_doc"]["{Func}"].call(), SYS.DAQ.JavaLikeCalc["lib_doc"].{Func}(). Де {Func} — ідентифікатор функції у бібліотеці.

Назви елементів та їх параметрів доступні на мовах: Англійська, Українська та Російська. Їх вихідний код написано у мово(людська)-незалежному режимі з викликом функції перекладу tr() та переклад цих повідомлень також доступний Англійською, Українською та Російською.

Засновано: січень 2008р
Автор: Роман Савоченко <roman@oscada.org>
Версія: 2.0.3
Ліцензія: GPLv2
DOC: Libs_Documents|Libs/Documents

ru#DESCR:
Предоставляет комбинированную библиотеку отчётов, документов и связанных функций общей и промышленной автоматизации.

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

Для адресации к функции этой библиотеки можно использовать статический адрес вызова DAQ.JavaLikeCalc.lib_doc.{Func}() или динамический SYS.DAQ.JavaLikeCalc["lib_doc"]["{Func}"].call(), SYS.DAQ.JavaLikeCalc["lib_doc"].{Func}(). Где {Func} — идентификатор функции в библиотеке.

Названия элементов и их параметров доступны на языках: Английский, Украинский и Российский. Их исходный код написан в языко(человеческий)-независимом режиме с вызовом функции перевода tr() и перевод этих сообщений также доступен Английским, Украинским и Российским.

Основано: январь 2008г
Автор: Роман Савоченко <roman@oscada.org>
Версия: 2.0.3
Лицензия: GPLv2
DOC: Libs_Documents|Libs/Documents


ID: regEl
NAME: Regulation elements
DB: flb_regEl
uk#NAME: Елементи регулювання
ru#NAME: Элементы регулирования
DESCR:
Regulation elements library of block-schemes of the module DAQ.BlockCalc.

The library is created to provide functions of different control algorithms and it can be used in programmable logic controllers (PLC) based on OpenSCADA for construction control schemes in the module DAQ.BlockCalc. The library is not static, but based on the module JavaLikeCalc, allowing to create calculations on the Java-like language. The functions' names and its parameters are available in languages: English, Ukrainian and Russian.

To addressing the library functions you can use the static call address DAQ.JavaLikeCalc.lib_regEl.{Func}() or dynamic SYS.DAQ.JavaLikeCalc["lib_regEl"]["{Func}"].call(), SYS.DAQ.JavaLikeCalc["lib_regEl"].{Func}()". Where {Func} — function identifier in the library.

Founded: January 2010
Author: Roman Savochenko <roman@oscada.org>
Sponsored by: DIYA Ltd
Version: 1.0.0
License: GPLv2
DOC: Libs_Regulation_elements|Libs/Regulation_elements

uk#DESCR:
Бібліотека елементів регулювання блокових схем модуля DAQ.BlockCalc.

Бібліотека створюється для надання функцій різних алгоритмів контролю та вона може бути використана у програмованих логічних контролерах (PLC) заснованих на OpenSCADA для побудови схем контролю у модулі DAQ.BlockCalc. Бібліотека не є статичною, а будується на основі модуля JavaLikeCalc, який дозволяє створювати обчислення на мові схожій на Java. Назви функцій та їх параметрів доступні на мовах: Англійська, Українська та Російська.

Для адресації до функцій цієї бібліотеки можна використати статичну адресу виклику DAQ.JavaLikeCalc.lib_regEl.{Func}() або динамічну SYS.DAQ.JavaLikeCalc["lib_regEl"]["{Func}"].call(), SYS.DAQ.JavaLikeCalc["lib_regEl"].{Func}(). Де {Func} — ідентифікатор функції у бібліотеці.

Засновано: Січень 2010
Автор: Роман Савоченко <roman@oscada.org>
Спонсоровано: ТОВ "ДІЯ"
Версія: 1.0.0
Ліцензія: GPLv2
DOC: Libs_Regulation_elements|Libs/Regulation_elements

ru#DESCR:
Библиотека элементов регулирования блочных схем модуля DAQ.BlockCalc.

Библиотека создаётся для предоставления функций различных алгоритмов контроля и она может быть использована в программированных логических контроллерах (PLC) основанных на OpenSCADA для построения схем контроля в модуле DAQ.BlockCalc. Библиотека не является статической, а строится на основе модуля JavaLikeCalc, позволяющего создавать вычисления на Java-подобном языке. Названия функций и их параметров доступны на языках: Английский, Украинский и Российский.

Для адресации к функции этой библиотеки можно использовать статический адрес вызова DAQ.JavaLikeCalc.lib_regEl.{Func}() или динамический SYS.DAQ.JavaLikeCalc["lib_regEl"]["{Func}"].call(), SYS.DAQ.JavaLikeCalc["lib_regEl"].{Func}(). Где {Func} — идентификатор функции в библиотеке.

Основано: Январь 2010
Автор: Роман Савоченко <roman@oscada.org>
Спонсировано: ООО "ДІЯ"
Версия: 1.0.0
Лицензия: GPLv2
DOC: Libs_Regulation_elements|Libs/Regulation_elements


ID: Controller
NAME: Controllers
DB: lib_Controllers
uk#NAME: Контролери
ru#NAME: Контроллеры
DESCR:
Library of programs of controllers based on JavaLikeCalc.

Author: Roman Savochenko <roman@oscada.org>
Version: 1.1.1
License: GPLv2

uk#DESCR:
Програми контролерів базованих на JavaLikeCalc.

Автор: Роман Савоченко <roman@oscada.org>
Версія: 1.1.1
Ліцензія: GPLv2

ru#DESCR:
Программы контроллеров основанных на JavaLikeCalc.

Автор: Роман Савоченко <roman@oscada.org>
Версия: 1.1.1
Лицензия: GPLv2


ID: web
NAME: XHTML-template
DB: flb_web
uk#NAME: XHTML-шаблон
ru#NAME: XHTML-шаблон
DESCR:
Pages processing functions library for XHTML-template user's Web-interface.

Author: Roman Savochenko
Version: 0.2.0
License: GPL

uk#DESCR:
Бібліотека функцій обробки сторінок XHTML-шаблонів користувацткого Web-інтерфейсу.

Автор: Роман Савоченко <roman@oscada.org>
Версія: 0.2.0
Ліцензія: GPL

ru#DESCR:
Библиотека функций обработки страниц XHTML-шаблонов пользовательского Web-интерфейса.

Автор: Роман Савоченко <roman@oscada.org>
Версия: 0.2.0
Лицензия: GPL


# flb_doc_io

F_ID: diagram
ID: tmpl
NAME: SVG-template
uk#NAME: Шаблон
ru#NAME: Шаблон
DEF:
<svg xmlns="http://www.w3.org/2000/svg" version="1.1" sclMarkFont="Arial 10" sclHor="2" sclVer="3" sclColor="gray" sclMarkColor="gray">
    <style type="text/css">
	    #scVer rect { stroke: none; }
	    #scVer text { stroke: none; }
	    #scHor rect { stroke: none; }
	    #scHor text { stroke: none; }
	    #drawArea path { fill: none; }
    </style>
    <!--Draw grid and markers-->
    <g id="scVer" />
    <g id="scHor" />
    <!--Curves area -->
    <g id="drawArea" />
</svg>


# lib_servProc_io

F_ID: docOffLine
ID: pages
NAME: Pages list of "{wiki}:{langs}:{dest}"
DEF:
Documents:en,uk,ru:index.html
Documents/Release_0.9:en,uk,ru:Release_0.9.html
Documents/Release_0.9/Updating_0.8.0_LTS:en,uk,ru:Updating_0.8.0.html
Works/Technical_Support/Agreement:en,uk,ru:Technical_Support_Agreement.html
About:en,uk,ru:About.html
Documents/Terms:en,uk,ru:Terms.html
Functions_and_demands:en,uk,ru:Functions_and_demands.html
Works/To_do:en:To_do.html
Documents/FAQ:en,uk,ru:FAQ.html
Documents/Quick_start:en,uk,ru:Quick_start.html
Documents/Program_manual:en,uk,ru:Program_manual.html
Documents/How_to:en,uk,ru:How_to.html
Documents/How_to/Install:en,uk,ru:How_to_Install.html
Documents/How_to/Live_disk:en,uk,ru:How_to_Live_disk.html
Documents/How_to/Violations,_alarms_and_notifications:en,uk,ru:How_to_Violations.html
Documents/How_to/Cyclic_programming:en,uk,ru:How_to_Cyclic_programming.html
Documents/How_to/Debug:en,uk,ru:How_to_Debug.html
Documents/How_to/Transferring_project_configuration:en,uk,ru:How_to_Transferring_project_configuration.html
Documents/How_to/Build_from_source:en,uk,ru:How_to_Build_from_source.html
Documents/How_to/Crash_report:en,uk,ru:How_to_Crash_report.html
Documents/How_to/Create_module:en,uk,ru:How_to_Create_module.html
Documents/DAQ:en,uk,ru:DAQ.html
Documents/User_API:en,uk,ru:User_API.html
Documents/API:en:API.html
Modules/SQLite:en,uk,ru:Modules/SQLite.html
Modules/MySQL:en,uk,ru:Modules/MySQL.html
Modules/FireBird:en,uk,ru:Modules/FireBird.html
Modules/PostgreSQL:en,uk,ru:Modules/PostgreSQL.html
Modules/DBGate:en,uk:Modules/DBGate.html
Modules/DBF:en,uk,ru:Modules/DBF.html
Modules/LDAP:en,uk,ru:Modules/LDAP.html
Modules/Sockets:en,uk,ru:Modules/Sockets.html
Modules/Serial:en,uk,ru:Modules/Serial.html
Modules/SSL:en,uk,ru:Modules/SSL.html
Modules/SelfSystem:en,uk,ru:Modules/SelfSystem.html
Modules/UserProtocol:en,uk,ru:Modules/UserProtocol.html
Modules/HTTP:en,uk,ru:Modules/HTTP.html
Modules/JavaLikeCalc:en,uk,ru:Modules/JavaLikeCalc.html
Modules/LogicLev:en,uk,ru:Modules/LogicLev.html
Modules/BlockCalc:en,uk,ru:Modules/BlockCalc.html
Modules/DAQGate:en,uk,ru:Modules/DAQGate.html
Modules/System:en,uk,ru:Modules/System.html
Modules/ModBus:en,uk,ru:Modules/ModBus.html
Modules/DCON:en,uk,ru:Modules/DCON.html
Modules/OPC_UA:en,uk,ru:Modules/OPC_UA.html
Modules/SNMP:en,uk,ru:Modules/SNMP.html
Modules/ICP_DAS:en,uk,ru:Modules/ICP_DAS.html
Modules/Siemens:en,uk,ru:Modules/Siemens.html
Modules/DiamondBoards:en,uk,ru:Modules/DiamondBoards.html
Modules/Comedi:en,uk,ru:Modules/Comedi.html
Modules/SoundCard:en,uk,ru:Modules/SoundCard.html
Modules/BFN:en,uk,ru:Modules/BFN.html
Modules/SMH2Gi:en,uk,ru:Modules/SMH2Gi.html
Modules/GPIO:en,uk,ru:Modules/GPIO.html
Modules/FSArch:en,uk,ru:Modules/FSArch.html
Modules/DBArch:en,uk,ru:Modules/DBArch.html
Modules/VCAEngine:en,uk,ru:Modules/VCAEngine.html
Modules/QTStarter:en,uk,ru:Modules/QTStarter.html
Modules/QTCfg:en,uk,ru:Modules/QTCfg.html
Modules/Vision:en,uk,ru:Modules/Vision.html
Modules/WebCfgD:en,uk,ru:Modules/WebCfgD.html
Modules/WebCfg:en,uk,ru:Modules/WebCfg.html
Modules/WebVision:en,uk,ru:Modules/WebVision.html
Modules/WebUser:en,uk,ru:Modules/WebUser.html
Modules/FLibSYS:en,uk,ru:Modules/FLibSYS.html
Modules/SystemTests:en,uk,ru:Modules/SystemTests.html
Modules/FLibMath:en,uk,ru:Modules/FLibMath.html
Modules/FLibComplex1:en,uk,ru:Modules/FLibComplex1.html
Libs/Main:en,uk,ru:Libs_Main.html
Libs/Devices:en,uk,ru:Libs_Devices.html
Libs/LowLevelDevices:en,uk,ru:Libs_LowLevelDevices.html
Libs/Service_procedures:en,uk,ru:Libs_Service_procedures.html
Libs/Regulation_elements:en,uk,ru:Libs_Regulation_elements.html
Libs/Technological_apparatuses:en,uk,ru:Libs_Technological_apparatuses.html
Libs/Main_graphical_elements:en,uk,ru:Libs_Main_graphical_elements.html
Libs/Mnemo_elements:en,uk,ru:Libs_Mnemo_elements.html
Libs/Electrical_elements:en,uk,ru:Libs_Electrical_elements.html
Libs/Documents:en,uk,ru:Libs_Documents.html
Libs/Prescriptions:en,uk,ru:Libs_Prescriptions.html


# WebUser_uPg

ID: tmpl
NAME: XHTML-template
uk#NAME: XHTML-шаблон
DESCR: Site from XHTML template.
uk#DESCR: Сайт із XHTML шаблону
ru#DESCR: Сайт из XHTML шаблона.
ru#NAME: XHTML-шаблон
PROG:
JavaLikeCalc.JavaScript
var pgDir = "Web/";
var firstEl = url.parsePath(0);
var procPg = false;
var tmplPg = "";
var tmplPrcPg = false;
var pgTree = false;
var treeEl = false;
var err = false;
var isUser = SYS.Security.access(user,4,"root","Web",0440);
var isRootUser = SYS.Security.access(user,4,"root","WebRoot",0440);

//> Pages requests process
if(!firstEl.length || (tmplPg=SYS.fileRead(pgDir+firstEl+".html")).length)
{
	//> Early call page's script
	if(tmplPg.length)
	{
		procPg = SYS.DAQ.JavaLikeCalc.lib_web[(URLprms["script"].isEVal() ? firstEl : URLprms["script"])];
		if(typeof(procPg) == "TCntrNode")
		{
			tmplPrcPg = procPg.call(URLprms,tmplPg,cnts,user);
			//>> Check for full XML or resource request
			var poff = 0;
			if(tmplPrcPg.parse(0,"\n",poff) == "200 OK")
			{
				while((pEl=tmplPrcPg.parse(0,"\n",poff)).length) HTTPvars[pEl.parse(0,":")] = pEl.parse(1,":");
				page = tmplPrcPg.slice(poff);
				return "200 OK";
			}
		}
		else tmplPrcPg = tmplPg;
	}

	//> Parse template
	pgTree = SYS.XMLNode();
	err = pgTree.load(pgDir+"main.html",true,true);

	//> Page time place
	pgTree.getElementBy("time_vl").setAttr("value",SYS.time());
	var sessLife = SYS.XMLNode("get").setAttr("path","/sub_Protocol/mod_HTTP/%2fprm%2flf_tm");
	SYS.cntrReq(sessLife);
	pgTree.getElementBy("ses_vl").setAttr("value",sessLife.text().toInt()*60);

	//> Check access to WEB resource
	if(!user.length || !isUser)
	{
		pgTree.getElementBy("ses_vl").setAttr("value",10);
		pgTree.getElementBy("menu_l").setAttr("style","visibility : hidden;");
		pgTree.getElementBy("menu_r").setAttr("style","visibility : hidden;");
		pgTree.getElementBy("status").setAttr("style","visibility : hidden;");
		tmplPrcPg = SYS.fileRead(pgDir+"loginError.html");
	}
	//> Process include page template
	else if(tmplPg.length)
	{
		//>> Select page display
		treeEl = pgTree.getElementBy(firstEl);
		if(typeof(treeEl) == "XMLNode")
			treeEl.setAttr("class",treeEl.attr("class").replace(new RegExp("menu([^\"]*)"),"menuSel$1"));
	}
	else tmplPrcPg = SYS.fileRead(pgDir+"welcome.html");

	//> Status make
	pgTree.getElementBy("path").setText("/"+firstEl);
	pgTree.getElementBy("user_st").childIns(0,"span").setText(user+"("+(isRootUser?"суперпользователь":"пользователь")+")      ");

	//> Super user access
	if(isUser && !isRootUser)
	{
		pgTree.getElementBy("cfg").parent().setAttr("style","visibility : hidden;");
		pgTree.getElementBy("devices").parent().setAttr("style","visibility : hidden;");

		treeEl = SYS.XMLNode("get").setAttr("path","/sub_Security/usr_"+user+"/%2fprm%2fldscr");
		SYS.cntrReq(treeEl);
		//>> Report disable
		re=treeEl.text().match("Report:\\s+([^\\n]*)");
		if(!re.length || re[1] != "true") pgTree.getElementBy("report").parent().setAttr("style","visibility : hidden;");
		//>> Subsystem's permition
		var catLs = SYS.XMLNode("get").setAttr("path","/DAQ/ModBus/ZegBee/%2fprm%2fprm");
		SYS.cntrReq(catLs);
		for(var i = 0; i < catLs.childSize(); i++)
		{
			re=treeEl.text().match("sub_"+catLs.childGet(i).attr("id")+":\\s+([^\\n]*)");
			if(!re.length || re[1] == "--") pgTree.getElementBy(catLs.childGet(i).attr("id")).parent().setAttr("style","visibility : hidden;");
		}
	}

	//> Save template
	page = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"+
			"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n"+
			pgTree.save();
	page = page.replace("#####CONTEXT#####",tmplPrcPg);
	return "200 OK";
}

//> Resources get process
if(HTTPreq == "GET")
{
	page = SYS.fileRead(pgDir+url);
	if(!page.length) { page = "Resource '"+url+"' call error!"; return "404 Not Found"; }
	//>> Extesion types processing
	var fext = url.lastIndexOf(".");
	fext = (fext > 0) ? url.slice(fext+1) : "";
	if(fext == "png" || fext == "jpg" || fext == "ico") HTTPvars["Content-Type"] = "image/"+fext;
	else if(fext == "css" || fext == "html" || fext == "xml") HTTPvars["Content-Type"] = "text/"+fext;
	else if(fext == "js") HTTPvars["Content-Type"] = "text/javascript";
	//SYS.messDebug("TEST Web","TEST 10: '"+fext+"' .");
	return "200 OK";
}

return "404 Not Found";


# Trs

base:
Frequency was bad (previous XtalStat was XPROB_FREQ) and frequency is now in range, but life is less than 3%.


base:
Unable to determine rate because of a computation error, most likely caused by a parameter (density, z-ratio, etc) having a zero or otherwise invalid (non numeric or infinity) value.


base:
Binary Counter (20) or Frozen Binary Counter (21): unsupported variant '%1', the processing terminated


base:
Binary Counter Changed (22) or Frozen Binary Counter Changed (23): unsupported variant '%1', the processing terminated


# tmplib_DevLib

ID: SCU750
NAME: EDWARDS TURBOMOLECULAR PUMPS
DESCR:
Typical EDWARDS TURBOMOLECULAR PUMPS (http://edwardsvacuum.com) data acquisition by SCU750 Cotrol Unit protocol.

Author: Roman Savochenko <roman@oscada.org>
Sponsored: Vasiliy Grigoriev from "Vacuum technologies laboratory (http://e-beam.ru)".
Version: 1.0.0
License: GPLv2

PROGRAM:
JavaLikeCalc.JavaScript
if(f_start) {
	version = "";
	operModes = new Object();
	operModes[1] = tr("Levitation");
	operModes[2] = tr("No Levitation");
	operModes[3] = tr("Acceleration");
	operModes[4] = tr("Normal");
	operModes[5] = tr("Deceleration (Brake)");
	operModes[6] = tr("Autotest");
	operModes[7] = tr("Tuning");
	operModes[8] = tr("Tuning Complete");
}

tr = SYS.Transport.Serial.nodeAt("out_"+transport);
req = SYS.XMLNode("mess").setAttr("ProtIt","SCU750").setAttr("addr",addr);

//======= Commands =========
//START, STOP and RESET process
if(comReset == true) req.setText(" E04");
else if(comStop == true) req.setText(" E02");
else if(comStart == true) req.setText(" E01");
else req.setText("");
if(req.text().length) { tr.messIO(req,"UserProtocol"); comReset=comStop=comStart=false; }

//Speed setpoint set
if(spSpeed != spSpeedPrev) {
	req.setText(" h"+spSpeed.toString(16,4));
	tr.messIO(req,"UserProtocol");
	spSpeedPrev = spSpeed;
}

//======= Data getting (by self bigger period) ========
if((cnt++)%max(1,perGet*f_frq))	return;
t_err = "";

//Read version, single
if(!version.length || version.isEVal()) {
	req.setText("?V");
	tr.messIO(req,"UserProtocol");
	if(req.attr("err").length) { t_err = req.attr("err"); version = EVAL_STR; }
	else {
		if(req.text().length != 42) version = EVAL_STR;
		else {
			CUSv = "";
			lstNoSp = 0;
			for(i_s = 2; i_s < 32; i_s+=2) {
				cod = req.text().slice(i_s,i_s+2).toInt(16);
				CUSv += SYS.strFromCharCode(cod);
				if(cod != 0x20) lstNoSp = i_s/2;
			}
			version = "Contr. Unit Soft V.="+CUSv.slice(0,lstNoSp)+"; "
					    "Motor Drive Soft V.="+req.text().charAt(35)+"."+req.text().charAt(36)+"; "
					    "DSP Soft V.="+req.text().charAt(39)+"."+req.text().charAt(40);
		}
	}
}

//Read rotational speed.
if(t_err.length) tTMS = tMotor = rotSpeed = EVAL_INT;
else {
	req.setText("?[");
	tr.messIO(req,"UserProtocol");
	if(req.attr("err").length) { t_err = req.attr("err"); tTMS = tMotor = rotSpeed = EVAL_INT; }
	else {
		tTMS = req.text().slice(32,36).toInt(16);
		tMotor = req.text().slice(36,40).toInt(16);
		rotSpeed = req.text().slice(50,54).toInt(16);
	}
}

//Pump operation mode and errors read
if(t_err.length) { operMode = EVAL_INT; errors = EVAL_STR; }
else {
	req.setText("?M");
	tr.messIO(req,"UserProtocol");
	if(req.attr("err").length) { t_err = req.attr("err"); operMode = EVAL_INT; errors = EVAL_STR; }
	else {
		oMode = req.text().slice(2,4).toInt(16);
		operMode = oMode.toString()+":"+(operModes[oMode].isEVal()?tr("Unknown"):operModes[oMode]);
		//SYS.messDebug("CNTR","pumpOperMode: "+pumpOperMode);
		
		errCnt = req.text().slice(4,6).toInt(16);
		errors = "";
		for(i_e = 0; i_e < errCnt; i_e++)
			errors += req.text().slice(6+i_e*2,8+i_e*2)+"; ";
	}
}

//Events read
if(t_err.length)	events = EVAL_STR;
else {
	req.setText("?g");
	tr.messIO(req,"UserProtocol");
	if(req.attr("err").length) { t_err = req.attr("err"); events = EVAL_STR; }
	else {
		errCnt = req.text().slice(2,4).toInt(16);
		events = "";
		for(i_e = 0; i_e < errCnt; i_e++)
			events += req.text().slice(4+i_e*2,6+i_e*2)+"; ";
	}
}

//Counters
if(t_err.length) { snCntrUnit = snPump = EVAL_STR; cntPumpHour = cntCntrUnitHour = cntStart = EVAL_REAL; }
else {
	req.setText("?c");
	tr.messIO(req,"UserProtocol");
	if(req.attr("err").length) { t_err = req.attr("err"); snCntrUnit = snPump = EVAL_STR; cntPumpHour = cntCntrUnitHour = cntStart = EVAL_REAL; }
	else {
		snCntrUnit = req.text().slice(2,12);
		snPump = req.text().slice(12,22);
		cntPumpHour = req.text().slice(22,30).toInt(16);
		cntCntrUnitHour = req.text().slice(30,38).toInt(16);
		cntStart = req.text().slice(38,46).toInt(16);
	}
}

//Read setpoints
if(t_err.length)	spSpeed = spSpeedPrev = spTMSt = EVAL_INT;
else {
	req.setText("?d");
	tr.messIO(req,"UserProtocol");
	if(req.attr("err").length) { t_err = req.attr("err"); spSpeed = spSpeedPrev = spTMSt = EVAL_INT; }
	else {
		spSpeed = spSpeedPrev = req.text().slice(2,6).toInt(16);
		spTMSt = req.text().slice(6,10).toInt(16);
	}
}

f_err = t_err;


ID: TMH
NAME: Power supply for turbomolecular pumps
DESCR:
Power supply for turbomolecular pumps of firm SHIMADZU (http://www.shimadzu.com), model EI-R04M.

Author: Roman Savochenko <roman@oscada.org>
Sponsored: Vasiliy Grigoriev from "Vacuum technologies laboratory (http://e-beam.ru)".
Version: 1.0.0
License: GPLv2

PROGRAM:
JavaLikeCalc.JavaScript
tr = SYS.Transport.Serial.nodeAt("out_"+transport);
req = SYS.XMLNode("mess").setAttr("ProtIt","TMH").setAttr("addr",addr);

if(f_start) {
	modelID = "";
	operModes = new Object();
	//Modes
	operModes["NS"] = "1:"+tr("Levitation");
	operModes["NA"] = "3:"+tr("Acceleration");
	operModes["NN"] = "4:"+tr("Normal");
	operModes["NB"] = "5:"+tr("Deceleration");
	operModes["FS"] = "6:"+tr("Stop operation failure");
	operModes["FF"] = "7:"+tr("Idling failure");
	operModes["FR"] = "8:"+tr("Regeneration breaking failure");
	operModes["FB"] = "9:"+tr("Deceleration failure");
	//Conrols
	operModes["LL"] = tr("Local");
	operModes["LR"] = tr("Remote");
	operModes["LC"] = "RS-232C";
	operModes["LD"] = "RS-485";

	//Set to Interactive
	req.setText("LN");
	tr.messIO(req,"UserProtocol");
}

//======= Commands =========
//START, STOP and RESET process
if(comReset == true)			req.setText("RR");
else if(comStop == true)		req.setText("RP");
else if(comStart == true)	req.setText("RT");
else req.setText("");
if(req.text().length)	{ tr.messIO(req,"UserProtocol"); comReset = comStop = comStart = false; }

//Interactive, Autonomous
if(comInteract == true)		req.setText("LN");
else if(comAutonom == true)	req.setText("LF");
else req.setText("");
if(req.text().length)	{ tr.messIO(req,"UserProtocol"); comInteract = comAutonom = false; }

//======= Data getting (by self bigger period) ========
if((cnt++)%max(1,perGet*f_frq))	return;
t_err = "0";

//Oper mode
req.setText("CS");
tr.messIO(req,"UserProtocol");
if(req.attr("err").length) { t_err = req.attr("err"); operMode = EVAL_STR; }
else operMode = /*req.text().slice(2)+":"+*/operModes[req.text().slice(0,2)];

//Oper control
if(t_err.toInt())	operCntr = EVAL_STR;
else {
	req.setText("LS");
	tr.messIO(req,"UserProtocol");
	if(req.attr("err").length) { t_err = req.attr("err"); operCntr = EVAL_STR; }
	else operCntr = operModes[req.text().slice(0,2)];
}

//Alarms list obtain
if(t_err.toInt())	errors = EVAL_STR;
else {
	errors = "";
	for(i = 0; true; i++) {
		req.setText("CF"+i.toString(10,2));
		tr.messIO(req,"UserProtocol");
		if(req.attr("err").length) { t_err = req.attr("err"); errors = EVAL_STR; break; }
		//SYS.messDebug("TMH","Result: "+req.text());
		if(req.text().slice(0,2) != "CA")	break;
		errors += req.text().slice(2)+";";
		continue;
	}
}

//Get parameters
// Model ID
if(t_err.toInt())	modelID = EVAL_STR;
else if(!modelID.length || modelID == EVAL_STR) {
	req.setText("PR01");
	tr.messIO(req,"UserProtocol");
	if(req.attr("err").length) { t_err = req.attr("err"); modelID = EVAL_STR;}
	else if(req.text().slice(0,2) != "PA") modelID = EVAL_STR;
	else modelID = "TMP-"+req.text().slice(4);
}

// Rotation speed
if(t_err.toInt())	rotSpeed = EVAL_INT;
else {
	req.setText("PR03");
	tr.messIO(req,"UserProtocol");
	if(req.attr("err").length) { t_err = req.attr("err"); rotSpeed = EVAL_INT;}
	else if(req.text().slice(0,2) != "PA") rotSpeed = EVAL_INT;
	else rotSpeed = req.text().slice(4).toInt()*10;
}

// Current
if(t_err.toInt())	I = EVAL_REAL;
else {
	req.setText("PR04");
	tr.messIO(req,"UserProtocol");
	if(req.attr("err").length) { t_err = req.attr("err"); I = EVAL_REAL;}
	else if(req.text().slice(0,2) != "PA") I = EVAL_REAL;
	else I = req.text().slice(4).toInt()/10;
}

// Axle 1 disbalance
if(t_err.toInt())	axle1disb = EVAL_INT;
else {
	req.setText("PR21");
	tr.messIO(req,"UserProtocol");
	if(req.attr("err").length) { t_err = req.attr("err"); axle1disb = EVAL_INT;}
	else if(req.text().slice(0,2) != "PA") axle1disb = EVAL_INT;
	else axle1disb = req.text().slice(4).toInt();
}

// Axle 2 disbalance
if(t_err.toInt())	axle2disb = EVAL_INT;
else {
	req.setText("PR22");
	tr.messIO(req,"UserProtocol");
	if(req.attr("err").length) { t_err = req.attr("err"); axle2disb = EVAL_INT;}
	else if(req.text().slice(0,2) != "PA") axle2disb = EVAL_INT;
	else axle2disb = req.text().slice(4).toInt();
}

// MP X1
if(t_err.toInt())	MP_X1 = EVAL_INT;
else {
	req.setText("PR26");
	tr.messIO(req,"UserProtocol");
	if(req.attr("err").length) { t_err = req.attr("err"); MP_X1 = EVAL_INT;}
	else if(req.text().slice(0,2) != "PA") MP_X1 = EVAL_INT;
	else MP_X1 = req.text().slice(4).toInt();
}

// MP Y1
if(t_err.toInt())	MP_Y1 = EVAL_INT;
else {
	req.setText("PR27");
	tr.messIO(req,"UserProtocol");
	if(req.attr("err").length) { t_err = req.attr("err"); MP_Y1 = EVAL_INT;}
	else if(req.text().slice(0,2) != "PA") MP_Y1 = EVAL_INT;
	else MP_Y1 = req.text().slice(4).toInt();
}

// MP X2
if(t_err.toInt())	MP_X2 = EVAL_INT;
else {
	req.setText("PR28");
	tr.messIO(req,"UserProtocol");
	if(req.attr("err").length) { t_err = req.attr("err"); MP_X2 = EVAL_INT;}
	else if(req.text().slice(0,2) != "PA") MP_X2 = EVAL_INT;
	else MP_X2 = req.text().slice(4).toInt();
}

// MP Y2
if(t_err.toInt())	MP_Y2 = EVAL_INT;
else {
	req.setText("PR29");
	tr.messIO(req,"UserProtocol");
	if(req.attr("err").length) { t_err = req.attr("err"); MP_Y2 = EVAL_INT;}
	else if(req.text().slice(0,2) != "PA") MP_Y2 = EVAL_INT;
	else MP_Y2 = req.text().slice(4).toInt();
}

// MP Z
if(t_err.toInt())	MP_Z = EVAL_INT;
else {
	req.setText("PR30");
	tr.messIO(req,"UserProtocol");
	if(req.attr("err").length) { t_err = req.attr("err"); MP_Z = EVAL_INT;}
	else if(req.text().slice(0,2) != "PA") MP_Z = EVAL_INT;
	else MP_Z = req.text().slice(4).toInt();
}

f_err = t_err;


ID: TM510x
NAME: Elemer TM510x
DESCR:
Multi-channels thermometer Elemer TM5102 and TM5103 of the firm Elemer (http://www.elemer.ru).

Author: Roman Savochenko <roman@oscada.org>
Version: 1.0.0
License: GPLv2

PROGRAM:
JavaLikeCalc.JavaScript
if(f_start) devTp = EVAL_INT;

tr = SYS.Transport.Serial.nodeAt("out_"+transport);
req = SYS.XMLNode("mess").setAttr("ProtIt", "TM510x").setAttr("addr", addr);

t_err = "";

//Device type get
if(devTp.isEVal() || !devTp) {
	req.setText("0");
	tr.messIO(req, "UserProtocol");
	if(req.attr("err").length)	t_err = req.attr("err");
	else devTp = req.text().toInt();
}

//Inputs read
errors = "";
if(t_err.length) in1 = in2 = in3 = in4 = in5 = in6 = in7 = in8 = EVAL_REAL;
else {
	req.setText("6;0;8");
	tr.messIO(req,"UserProtocol");
	if(req.attr("err").length)
	{ t_err = req.attr("err"); in1 = in2 = in3 = in4 = in5 = in6 = in7 = in8 = EVAL_REAL; }
	else {
		off = 0;
		tvl = "";
		in1 = ((tvl=req.text().parse(0, ";", off))[0] == "$") ? EVAL_INT : tvl.toReal();
		errors += ((tvl[0] == "$") ? tvl.slice(1) : "0")+";";
		in2 = ((tvl=req.text().parse(0, ";", off))[0] == "$") ? EVAL_INT : tvl.toReal();
		errors += ((tvl[0] == "$") ? tvl.slice(1) : "0")+";";
		in3 = ((tvl=req.text().parse(0, ";", off))[0] == "$") ? EVAL_INT : tvl.toReal();
		errors += ((tvl[0] == "$") ? tvl.slice(1) : "0")+";";
		in4 = ((tvl=req.text().parse(0, ";", off))[0] == "$") ? EVAL_INT : tvl.toReal();
		errors += ((tvl[0] == "$") ? tvl.slice(1) : "0")+";";
		in5 = ((tvl=req.text().parse(0, ";", off))[0] == "$") ? EVAL_INT : tvl.toReal();
		errors += ((tvl[0] == "$") ? tvl.slice(1) : "0")+";";
		in6 = ((tvl=req.text().parse(0, ";", off))[0] == "$") ? EVAL_INT : tvl.toReal();
		errors += ((tvl[0] == "$") ? tvl.slice(1) : "0")+";";
		in7 = ((tvl=req.text().parse(0, ";", off))[0] == "$") ? EVAL_INT : tvl.toReal();
		errors += ((tvl[0] == "$") ? tvl.slice(1) : "0")+";";
		in8 = ((tvl=req.text().parse(0, ";", off))[0] == "$") ? EVAL_INT : tvl.toReal();
		errors += ((tvl[0] == "$") ? tvl.slice(1) : "0")+";";
	}
}

f_err = t_err;


ID: UPS
NAME: UPS (moved)
DESCR:
!!!!: Moved to the template library Main. Will be removed soon
Uninterruptible power supply unifying data for provide all the data into single attribute of object type "All items" for next the control as the object with the data provide as table, alarming and allowing set writable attributes. The template aimed for using with module "System" data source as "UPS" and widget "Main.objProps" as the data presenter. The template also you can use as example for create like other data unification as complex object with properties, alarming and writing.

Author: Roman Savochenko <roman@oscada.org>
Version: 1.2.1

PROGRAM:
JavaLikeCalc.JavaScript
if(f_start)	{ srcPrm = false; items = new Object(); conDelay_ = 0; }

alLev = 0;
tErr = "";

//Connect to source
if(typeof(srcPrm) != "TCntrNode:TValue:TParamContr") srcPrm = SYS.DAQ.nodeAt(srcAddr,".");
if(!srcPrm) { tErr = tr("No connection to source object"); alLev = 3; }
else if(srcPrm.err.get() != 0)	 { tErr = tr("Source error")+": "+srcPrm.err.get().parse(1,":"); alLev = 3; }
else {
	//Attributes list get and "items" update
	nLst = srcPrm.nodeList("a_");
	for(i_n = 0; i_n < nLst.length; i_n++) {
		aId = nLst[i_n].slice(2);
		aNd = srcPrm[nLst[i_n]];
		if(items[aId].isEVal()) {
			items[aId] = itW = new Object();
			itW.descr = aNd.descr();

			// Writeable check
			//SYS.messInfo("UPS test", aId+": aNd.flg()="+aNd.flg());
			if((itW.wr=!(aNd.flg()&0x04)) && aNd.flg()&0x01) {
				itW.wr = "";
				for(off = 0, pos = 0; (selId=aNd.values().parse(0,";",off)).length; pos++)
					itW.wr += ((selId==(selNm=aNd.selNames().parse(pos,";")))?selId:(selNm+" ("+selId+")"))+";";
			}
			itW.alarm = 0;
		}
		items[aId].val = aNd.get();
	}

	//Alarms process and mark
	varS = "ups_status";
	if(!(tP=srcPrm[varS]).isEVal() && !(tVl=tP.get()).isEVal()) {
		if(tVl == "OB")	{ items[varS].alarm = 1; tErr += tr("Status")+" \""+tr("On battery")+"\"; "; }
		else if(tVl == "LB")	{ items[varS].alarm = 2; tErr += tr("Status")+" \""+tr("Low battery")+"\"; "; }
		else if(tVl == "SD")	{ items[varS].alarm = 2; tErr += tr("Status")+" \""+tr("Shutdown load")+"\"; "; }
		else if(tVl.indexOf("ALARM") != -1)	{ items[varS].alarm = 2; tErr += tr("Status")+" \""+tr("ALARM")+"\"; "; }
		else items[varS].alarm = 0;
	}
	varS = "battery_packs";
	if(!(tP=srcPrm[varS]).isEVal() && !(tVl=tP.get()).isEVal()) {
		if(tVl.toInt() == 0)	{ items[varS].alarm = 2; tErr += tr("None of good battery present")+"; "; }
		else items[varS].alarm = 0;
	}
	varS = "battery_charge";
	if(!(tP=srcPrm[varS]).isEVal() && !(tVl=tP.get()).isEVal()) {
		if(tVl.toReal() < bChL) { items[varS].alarm = 1; tErr += tr("Battery charge low")+"; "; }
		else if(tVl.toReal() < bChLL) { items[varS].alarm = 2; tErr += tr("Battery charge critical")+"; "; }
		else items[varS].alarm = 0;
	}
	varS = "battery_packs_bad";
	if(!(tP=srcPrm[varS]).isEVal() && !(tVl=tP.get()).isEVal()) {
		if(tVl.toInt())	{ items[varS].alarm = 1; tErr += tr("Bad %1 batteries present").replace("%1",tVl); }
		else items[varS].alarm = 0;
	}
	varS = "input_voltage";
	if(!(tP=srcPrm[varS]).isEVal() && !(tVl=tP.get()).isEVal()) {
		if(tVl.toReal() > 10 && tVl.toReal() < inVL) { items[varS].alarm = 1; tErr += tr("Input voltage low")+"; "; }
		else if(tVl.toReal() > inVH) { items[varS].alarm = 1; tErr += tr("Input voltage high")+"; "; }
		else items[varS].alarm = 0;
	}
	varS = "input_frequency";
	if(!(tP=srcPrm[varS]).isEVal() && !(tVl=tP.get()).isEVal()) {
		if(tVl.toReal() < inFLL) { items[varS].alarm = 2; tErr += tr("Input frequency too low")+"; "; }
		else if(tVl.toReal() > inFHH)	{ items[varS].alarm = 2; tErr += tr("Input frequency too high")+"; "; }
		else if(tVl.toReal() < inFL) { items[varS].alarm = 1; tErr += tr("Input frequency low")+"; "; }
		else if(tVl.toReal() > inFH) { items[varS].alarm = 1; tErr += tr("Input frequency high")+"; "; }
		else items[varS].alarm = 0;
	}
	varS = "ups_load";
	if(!(tP=srcPrm[varS]).isEVal() && !(tVl=tP.get()).isEVal()) {
		if(tVl.toReal() > loadHH)		{ items[varS].alarm = 2; tErr += tr("UPS overloaded")+"; "; }
		else if(tVl.toReal() > loadH)	{ items[varS].alarm = 1; tErr += tr("UPS load high")+"; "; }
		else items[varS].alarm = 0;
	}
	varS = "ups_temperature";
	if(!(tP=srcPrm[varS]).isEVal() && !(tVl=tP.get()).isEVal()) {
		if(tVl.toReal() > tHH) 		{ items[varS].alarm = 2; tErr += tr("UPS overheated")+"; "; }
		else if(tVl.toReal() > tH)	{ items[varS].alarm = 1; tErr += tr("Temperature high")+"; "; }
		else items[varS].alarm = 0;
	}

	//Set variables process
	for(var aIt in items) {
		it = items[aIt];
		if(!it.set.isEVal()) {
			aNd = srcPrm["a_"+it.id];
			if(aNd.flg()&0x01 && (selV=it.set.match(".+\\((.+)\\)$")).length) it.set = selV[1];
			aNd.set(it.set);
			it.set = EVAL_REAL;
		}
		alLev = max(alLev, it.alarm);
	}
}

//SYS.messInfo("UPS test", "tErr="+tErr+"; alLev="+alLev);
tErr = tErr.length ? ""+alLev+":"+tErr : "0";

//Alarms forming
if(alDelay > 0 && conDelay_ <= 0 && tErr.toInt() != f_err.toInt())	tErr1 = tErr.toInt();
if(alDelay > 0 && conDelay_ > 0 && tErr.toInt() != tErr1)	{ conDelay_ = 0; tErr1 = tErr.toInt(); }
if(alDelay > 0 && conDelay_ < alDelay){ conDelay_ += 1/f_frq; return; }
if(tErr.toInt() && tErr.toInt() != f_err.toInt())	this.alarmSet(DESCR+": "+tErr.parse(1,":"), -(2+alLev));
else if(f_err.toInt() && !tErr.toInt())			this.alarmSet(DESCR+": "+tr("NORM"), 1);
f_err = tErr;
conDelay_ = 0;


ID: VKT7
NAME: VKT-7
DESCR:
Firm "Teplocom" (http://www.teplocom.spb.ru) computer "VKT-7" for complex heat measurement and counting. The device complex enough to provide more parameters, more history and accessed by a nonlinear Serial-based protocol at low speed. The template implements acquisition for all significant parameters, gets for their history by hours, days and result months. Also you can to append easily enough for processing of the remained parameters.

Author: Roman Savochenko <roman@oscada.org>
Sponsored: Vladislav Chubuk
Version: 1.0.0
License: GPLv2

PROGRAM:
JavaLikeCalc.JavaScript
using Special.FLibSYS;

if(f_start) {
	//Variables list prepare
	varsLs = new Object();
	//Тв1
	varsLs["t1_1"] = 0; varsLs["t2_1"] = 1; varsLs["t3_1"] = 2;		//t
	varsLs["V1_1"] = 3; varsLs["V2_1"] = 4;	varsLs["V3_1"] = 5;		//V
	varsLs["M1_1"] = 6;	varsLs["M2_1"] = 7;	varsLs["M3_1"] = 8;		//M
	varsLs["P1_1"] = 9;	varsLs["P2_1"] = 10;	//P
	varsLs["Mg_1"] = 11;	//Mg
	varsLs["Qo_1"] = 12;	//Qo
	varsLs["Qg_1"] = 13;	//Qg
	varsLs["dt_1"] = 14;	//dt
	varsLs["BNR_1"] = 17; varsLs["BOC_1"] = 18;//BNR and BOC
	varsLs["G1_1"] = 19; varsLs["G2_1"] = 20;	//G
	//Тв2
	varsLs["t1_2"] = 22; varsLs["t2_2"] = 23; varsLs["t3_2"] = 24;	//t
	varsLs["V1_2"] = 25; varsLs["V2_2"] = 26; varsLs["V3_2"] = 27;	//V
	varsLs["M1_2"] = 28; varsLs["M2_2"] = 29; varsLs["M3_2"] = 30;	//M
	varsLs["P1_2"] = 31; varsLs["P2_2"] = 32;	//P
	varsLs["Mg_2"] = 33;	//Mg
	varsLs["Qo_2"] = 34;	//Qo
	varsLs["Qg_2"] = 35;	//Qg
	varsLs["dt_2"] = 36;	//dt
	varsLs["BNR_2"] = 39; varsLs["BOC_2"] = 40;//BNR and BOC
	varsLs["G1_2"] = 41; varsLs["G2_2"] = 42;	//G

	//Buffers create
	bfH = vArhBuf(4/*Real*/, 10, 3600*1000000, true, false);
	bfD = vArhBuf(4/*Real*/, 10, 24*3600*1000000, true, false);
	bfM = vArhBuf(4/*Real*/, 10, 24*3600*1000000, true, false);
}

t_err = "";
//Imitation for values
if(imit > 0.1) {
	//SYS.messDebug("/VKT7/TMPL","imit="+t1_1+"; dt="+(imit*(rand(t1_1)-t1_1/2)/100));
	for(var cA in varsLs)
		if(cA.slice(0,2) == "dt") arguments[cA] = arguments["t1_"+cA.slice(3)]-arguments["t2_"+cA.slice(3)];
		else arguments[cA] += imit*(rand(arguments[cA])-arguments[cA]/2)/100;
	f_err = "0";
	return;
}

if(f_stop) {
	f_err = "";
	for(var cA in varsLs) arguments[cA] = EVAL_REAL;
	return;
}

//Set transport and RTS
if(f_start){ tr = SYS.nodeAt(trAddr,"."); tr.TS(true); valsPrec = false; valsSz = false; }
if(!tr)	t_err = "1:"+tr("Transport '%1' error.").replace("%1",trAddr);

req = SYS.XMLNode("mess").setAttr("ProtIt","VKT7").setAttr("addr",0);

//Session start
if(!t_err.length) {
	SYS.messDebug("/VKT7/TMPL",tr("Start session."));
	req.setAttr("err","2:"+tr("No connection")).setText(SYS.strFromCharCode(0x10,0x3F,0xFF,0x00,0x00,0xCC,0x80,0x00,0x00,0x00));
	tr.messIO(req,"UserProtocol");
	t_err = req.attr("err");
}

//Request for service information
if(!t_err.length && (f_start || firmVer.isEVal())) {
	SYS.messDebug("/VKT7/TMPL",tr("Request for service info."));
	req.setAttr("err","2:"+tr("No connection")).setText(SYS.strFromCharCode(0x03,0x3f,0xf9,0x00,0x00));
	tr.messIO(req,"UserProtocol");
	t_err = req.attr("err");
	if(!t_err.length) {
		rez = req.text();
		firmVer = (rez.charCodeAt(2)>>4)+(rez.charCodeAt(2)&0x0F)/10;
		abonId = rez.slice(7,7+8);
		netNum = rez.charCodeAt(15);
		repDay = rez.charCodeAt(16);
		modelImpl = rez.charCodeAt(17);
	}
}

//Request for counter time and hour archive begin
if(!t_err.length && (f_start || !lastHTm || !lastDTm || !lastResTm)) {
	SYS.messDebug("/VKT7/TMPL",tr("Request for counter time and hour archive begin."));
	req.setAttr("err","2:"+tr("No connection")).setText(SYS.strFromCharCode(0x03,0x3f,0xf6,0x00,0x00));
	tr.messIO(req,"UserProtocol");
	t_err = req.attr("err");
	if(!t_err.length) {
		rez = req.text();
		lastHTm = max(lastHTm, SYS.mktime(0,0,rez.charCodeAt(5),rez.charCodeAt(2),rez.charCodeAt(3)-1,2000+rez.charCodeAt(4)));
		diffTm = floor((SYS.time()-SYS.mktime(0,0,rez.charCodeAt(9),rez.charCodeAt(6),rez.charCodeAt(7)-1,2000+rez.charCodeAt(8)))/3600);
		leftHTm = (SYS.time()-lastHTm)/3600 - diffTm;
	}
	lastDTm = max(lastDTm, SYS.time()-maxDayDepth*24*3600);
	leftDTm = (SYS.time()-lastDTm)/(24*3600);
	lastResTm = max(lastResTm, SYS.time()-maxDayDepth*24*3600);
	leftResTm = (SYS.time()-lastResTm)/(31*24*3600);
}

//Request for dimensions and precisions
if(!t_err.length && (f_start || !valsPrec)) {
	SYS.messDebug("/VKT7/TMPL",tr("Request for dimensions and precisions."));
	req.setAttr("err","2:"+tr("No connection")).setText(SYS.strFromCharCode(0x10, 0x3F, 0xFF, 0x00, 0x00, 0x72,
		0x2C, 0x00, 0x00, 0x40, 0x07, 0x00,	//tTypeM
		0x2D, 0x00, 0x00, 0x40, 0x07, 0x00,	//GTypeM
		0x2E, 0x00, 0x00, 0x40, 0x07, 0x00,	//VTypeM
		0x2F, 0x00, 0x00, 0x40, 0x07, 0x00,	//MTypeM
		0x30, 0x00, 0x00, 0x40, 0x07, 0x00,	//PTypeM
		0x35, 0x00, 0x00, 0x40, 0x07, 0x00,	//QoTypeM
		0x37, 0x00, 0x00, 0x40, 0x07, 0x00,	//QntTypeHIM
		0x38, 0x00, 0x00, 0x40, 0x07, 0x00,	//QntTypeM
		0x39, 0x00, 0x00, 0x40, 0x01, 0x00,	//tTypeFractDiNum
		0x3B, 0x00, 0x00, 0x40, 0x01, 0x00,	//VTypeFractDigNum1
		0x3C, 0x00, 0x00, 0x40, 0x01, 0x00,	//MTypeFractDigNum1
		0x3D, 0x00, 0x00, 0x40, 0x01, 0x00,	//PTypeFractDigNum1
		0x3E, 0x00, 0x00, 0x40, 0x01, 0x00,	//dtTypeFractDigNum1
		0x42, 0x00, 0x00, 0x40, 0x01, 0x00,	//QoTypeFractDigNum1
		0x45, 0x00, 0x00, 0x40, 0x01, 0x00,	//VTypeFractDigNum2
		0x46, 0x00, 0x00, 0x40, 0x01, 0x00,	//MTypeFractDigNum2
		0x47, 0x00, 0x00, 0x40, 0x01, 0x00,	//PTypeFractDigNum2
		0x48, 0x00, 0x00, 0x40, 0x01, 0x00,	//dtTypeFractDigNum2
		0x4C, 0x00, 0x00, 0x40, 0x01, 0x00));	//QoTypeFractDigNum2
	tr.messIO(req,"UserProtocol");
	t_err = req.attr("err");
	if(!t_err.length) {
		req.setAttr("err","2:"+tr("No connection")).setText(SYS.strFromCharCode(0x03,0x3F,0xFE,0x00,0x00));
		tr.messIO(req,"UserProtocol");
		t_err = req.attr("err");
		if(!t_err.length) {
			rez = req.text();	off = 2;
			vLen = (rez.charCodeAt(off+1)<<8)|rez.charCodeAt(off);
			tTypeM = SYS.strCodeConv(rez.slice(off+2,off+2+vLen),"CP866","");	off += vLen+4;
			vLen = (rez.charCodeAt(off+1)<<8)|rez.charCodeAt(off);
			GTypeM = SYS.strCodeConv(rez.slice(off+2,off+2+vLen),"CP866","");	off += vLen+4;
			vLen = (rez.charCodeAt(off+1)<<8)|rez.charCodeAt(off);
			VTypeM = SYS.strCodeConv(rez.slice(off+2,off+2+vLen),"CP866","");	off += vLen+4;
			vLen = (rez.charCodeAt(off+1)<<8)|rez.charCodeAt(off);
			MTypeM = SYS.strCodeConv(rez.slice(off+2,off+2+vLen),"CP866","");	off += vLen+4;
			vLen = (rez.charCodeAt(off+1)<<8)|rez.charCodeAt(off);
			PTypeM = SYS.strCodeConv(rez.slice(off+2,off+2+vLen),"CP866","");	off += vLen+4;
			vLen = (rez.charCodeAt(off+1)<<8)|rez.charCodeAt(off);
			QoTypeM = SYS.strCodeConv(rez.slice(off+2,off+2+vLen),"CP866","");	off += vLen+4;
			vLen = (rez.charCodeAt(off+1)<<8)|rez.charCodeAt(off);
			QntTypeHIM = SYS.strCodeConv(rez.slice(off+2,off+2+vLen),"CP866","");	off += vLen+4;
			vLen = (rez.charCodeAt(off+1)<<8)|rez.charCodeAt(off);
			QntTypeM = SYS.strCodeConv(rez.slice(off+2,off+2+vLen),"CP866","");	off += vLen+4;
			valsPrec = new Object();
			valsPrec["tTypeFractDiNum"] = rez.charCodeAt(off);	off += 3;
			valsPrec["VTypeFractDigNum1"] = rez.charCodeAt(off);	off += 3;
			valsPrec["MTypeFractDigNum1"] = rez.charCodeAt(off);	off += 3;
			valsPrec["PTypeFractDigNum1"] = rez.charCodeAt(off);	off += 3;
			valsPrec["dtTypeFractDigNum1"] = rez.charCodeAt(off);	off += 3;
			valsPrec["QoTypeFractDigNum1"] = rez.charCodeAt(off);	off += 3;
			valsPrec["VTypeFractDigNum2"] = rez.charCodeAt(off);	off += 3;
			valsPrec["MTypeFractDigNum2"] = rez.charCodeAt(off);	off += 3;
			valsPrec["PTypeFractDigNum2"] = rez.charCodeAt(off);	off += 3;
			valsPrec["dtTypeFractDigNum2"] = rez.charCodeAt(off);	off += 3;
			valsPrec["QoTypeFractDigNum2"] = rez.charCodeAt(off);	off += 3;
		}
	}
}

//Request for values present list and size.
if(!t_err.length && (f_start || !valsSz || !valsSz.length)) {
	SYS.messDebug("/VKT7/TMPL",tr("Request for values present list and size."));
	req.setAttr("err","2:"+tr("No connection")).setText(SYS.strFromCharCode(0x03,0x3f,0xfc,0x00,0x00));
	tr.messIO(req,"UserProtocol");
	t_err = req.attr("err");
	if(!t_err.length) {
		rez = req.text();
		valsSz = new Array();
		for(off = 2; off < rez.length; off += 6)
			valsSz[rez.charCodeAt(off)] = rez.charCodeAt(off+4);
	}
}

//Readed items list write
if(!t_err.length) {
	SYS.messDebug("/VKT7/TMPL",tr("Readed items list write."));
	data = "";
	for(var cA in varsLs) {
		itId = varsLs[cA];
		if(!valsSz[itId].isEVal())	data += SYS.strFromCharCode(itId, 0x00, 0x00, 0x40, valsSz[itId], 0x00);
	}

	if(!data.length) {
		for(var cA in varsLs) arguments[cA] = EVAL_REAL;
		f_err = "10:"+tr("Data list for request empty.");
		return;
	}
	req.setAttr("err","2:"+tr("No connection")).setText(SYS.strFromCharCode(0x10,0x3f,0xff,0x00,0x00,data.length)+data);
	//SYS.messDebug("/VKT7/TMPL","SetDataList: "+Special.FLibSYS.strDec4Bin(req.text()));
	tr.messIO(req,"UserProtocol");
	t_err = req.attr("err");
}

//Read 0-current value(4), 1-hour archive(0) and 2-result month archive(3)
errAttrs = "";
for(i_dt = 0; !t_err.length && i_dt < 4; i_dt++) {
	tpReq = 4;																						//current
	if(i_dt == 1)			{ tpReq = 0; if(!arhH.length) continue; }		//hour archive
	else if(i_dt == 2)	{ tpReq = 1; if(!arhD.length) continue; }		//day archive
	else if(i_dt == 3)	{ tpReq = 3; if(!arhRes.length) continue; }	//result archive

	//Request for curent values (4).
	if(tpReq == 4 && !t_err.length) {
		SYS.messDebug("/VKT7/TMPL",tr("Request for curent values."));
		req.setAttr("err","2:"+tr("No connection")).setText(SYS.strFromCharCode(0x10,0x3f,0xfd,0x00,0x00,0x02,0x04,0x00));
		tr.messIO(req,"UserProtocol");
		t_err = req.attr("err");
	}

	//Request for archive values hour
	if(tpReq == 0) {
		if(!t_err.length) {
			if((SYS.time()-lastHTm-diffTm*3600)/3600 < 2) continue;	//No more ready hours present
			SYS.messDebug("/VKT7/TMPL",tr("Request for hour archive values."));
			req.setAttr("err","2:"+tr("No connection")).setText(SYS.strFromCharCode(0x10,0x3f,0xfd,0x00,0x00,0x02,tpReq,0x00));
			tr.messIO(req,"UserProtocol");
			t_err = req.attr("err");
		}

		// Set for hour archive value data
		if(!t_err.length) {
			SYS.messDebug("/VKT7/TMPL",tr("Request for set archive data."));
			stHour = stDay = stMonth = stYear = 0;
			SYS.localtime(lastHTm, 0, 0, stHour, stDay, stMonth, stYear);
			stHour++;
			rdTime = SYS.mktime(0, 0, stHour, stDay, stMonth, stYear);

			req.setAttr("err","2:"+tr("No connection")).setText(SYS.strFromCharCode(0x10,0x3f,0xfb,0x00,0x00,0x04,stDay,stMonth+1,stYear-2000,stHour));
			tr.messIO(req,"UserProtocol");
			t_err = req.attr("err");
			if(t_err.parse(1,":").toInt() == 3) { lastHTm = rdTime; leftHTm = (SYS.time()-lastHTm)/3600 - diffTm; t_err = ""; continue; }
		}
	}

	//Request for archive values day
	if(tpReq == 1) {
		if(!t_err.length) {
			if((SYS.time()-lastDTm-diffTm*3600)/(24*3600) < 1) continue;	//No more ready days present
			SYS.messDebug("/VKT7/TMPL",tr("Request for day archive values."));
			req.setAttr("err","2:"+tr("No connection")).setText(SYS.strFromCharCode(0x10,0x3f,0xfd,0x00,0x00,0x02,tpReq,0x00));
			tr.messIO(req,"UserProtocol");
			t_err = req.attr("err");
		}

		// Set for day archive value data
		if(!t_err.length) {
			SYS.messDebug("/VKT7/TMPL",tr("Request for set archive data."));
			stDay = stMonth = stYear = 0;
			SYS.gmtime(lastDTm, 0, 0, 0, stDay, stMonth, stYear);
			stDay++;
			rdDTime = SYS.timegm(0, 0, 0, stDay, stMonth, stYear);

			req.setAttr("err","2:"+tr("No connection")).setText(SYS.strFromCharCode(0x10,0x3f,0xfb,0x00,0x00,0x04,stDay,stMonth+1,stYear-2000,stHour));
			tr.messIO(req,"UserProtocol");
			t_err = req.attr("err");
			if(t_err.parse(1,":").toInt() == 3) { lastDTm = rdDTime; leftDTm = (SYS.time()-lastDTm)/(24*3600) - diffTm; t_err = ""; continue; }
		}
	}

	//Request for results month archive
	if(tpReq == 3) {
		if(!t_err.length) {
			if((SYS.time()-lastResTm-diffTm*3600)/(24*3600) < 31) continue;	//No more ready month present
			SYS.messDebug("/VKT7/TMPL",tr("Request for results month archive values."));
			req.setAttr("err","2:"+tr("No connection")).setText(SYS.strFromCharCode(0x10,0x3f,0xfd,0x00,0x00,0x02,tpReq,0x00));
			tr.messIO(req,"UserProtocol");
			t_err = req.attr("err");
		}
		// Set for month results archive value data
		if(!t_err.length) {
			SYS.messDebug("/VKT7/TMPL",tr("Request for set archive data."));
			stMonth = stYear = 0;
			SYS.gmtime(lastResTm, 0, 0, 0, 0, stMonth, stYear);
			stMonth++;
			rdResTime = SYS.timegm(0, 0, 0, repDay, stMonth, stYear);

			req.setAttr("err","2:"+tr("No connection")).setText(SYS.strFromCharCode(0x10,0x3f,0xfb,0x00,0x00,0x04,repDay,stMonth+1,stYear-2000,0));
			tr.messIO(req,"UserProtocol");
			t_err = req.attr("err");
			if(t_err.parse(1,":").toInt() == 3) { lastResTm = rdResTime; leftResTm = (SYS.time()-lastResTm)/(31*24*3600); t_err = ""; continue; }
		}
	}

	//Request for data read
	if(!t_err.length) {
		SYS.messDebug("/VKT7/TMPL",tr("Request for data read."));
		req.setAttr("err","2:"+tr("No connection")).setText(SYS.strFromCharCode(0x03,0x3F,0xFE,0x00,0x00));
		tr.messIO(req,"UserProtocol");
		t_err = req.attr("err");
		if(!t_err.length) {
			rez = req.text(); off = 2; vSz = 0;
			for(var cA in varsLs) {
				itId = varsLs[cA]; vSz = valsSz[itId];
				if(vSz.isEVal()) {
					if(tpReq == 4) arguments[cA] = EVAL_REAL;
					continue;
				}
				//SYS.messDebug("/VKT7/TMPL","off: "+off+"; itId: "+itId+"; vSz: "+vSz);
				if(rez.charCodeAt(off+vSz) == 0xC0) {
					for(pVal = 0, i_b = 0; i_b < vSz; i_b++) pVal = pVal | rez.charCodeAt(off+i_b)<<(i_b*8);
					//Float type values
					if(cA[0] == "G") pVal = floatMergeWord(pVal&0xFFFF, (pVal>>16)&0xFFFF);
					//Integer type values, negative process
					else if(pVal&(0x80<<(8*(vSz-1))))	pVal -= (1<<(8*vSz));
					// Type specific
					if(cA[0] == "t")						tmpVl = pVal/pow(10,valsPrec["tTypeFractDiNum"]);
					else if(cA[0] == "V")				tmpVl = pVal/pow(10,valsPrec["VTypeFractDigNum"+cA[3]]);
					else if(cA[0] == "M")				tmpVl = pVal/pow(10,valsPrec["MTypeFractDigNum"+cA[3]]);
					else if(cA[0] == "P")				tmpVl = pVal/pow(10,valsPrec["PTypeFractDigNum"+cA[3]]);
					else if(cA[0] == "Q")				tmpVl = pVal/pow(10,valsPrec["QoTypeFractDigNum"+cA[3]]);
					else if(cA.slice(0,2) == "dt")tmpVl = pVal/pow(10,valsPrec["dtTypeFractDigNum"+cA[3]]);
					else tmpVl = pVal;

					// Write current or archive
					if(tpReq == 4) {
						arguments[cA] = tmpVl;
						SYS.messDebug("/VKT7/TMPL",tr("Set current")+" "+cA+": "+tmpVl);
					}
					else if(!(aObj=vArh(this.nodePath(".")+"."+cA)).isNull()) {
						if(tpReq == 0) {
							bfH.set(tmpVl, rdTime, 0); aObj.copy(bfH, rdTime, 0, rdTime, 0, arhH);
							SYS.messDebug("/VKT7/TMPL",tr("Write to hour archive for time")+": "+rdTime+"; "+cA+": "+tmpVl);
						}
						if(tpReq == 1) {
							bfD.set(tmpVl, rdDTime, 0); aObj.copy(bfD, rdDTime, 0, rdDTime, 0, arhD);
							SYS.messDebug("/VKT7/TMPL",tr("Write to day archive for time")+": "+rdDTime+"; "+cA+": "+tmpVl);
						}
						else if(tpReq == 3) {
							bfM.set(tmpVl, rdResTime, 0); aObj.copy(bfM, rdResTime, 0, rdResTime, 0, arhRes);
							SYS.messDebug("/VKT7/TMPL",tr("Write to result month archive for time")+": "+rdResTime+"; "+cA+": "+tmpVl);
						}
					}
				}
				else if(tpReq == 4) { arguments[cA] = EVAL_REAL; errAttrs += ""+itId+"="+rez.charCodeAt(off+vSz).toString(16)+"; "; }
				off += vSz+2;
			}
			if(tpReq == 0) { lastHTm = rdTime; leftHTm = (SYS.time()-lastHTm)/3600 - diffTm; }
			else if(tpReq == 1) { lastDTm = rdDTime; leftDTm = (SYS.time()-lastDTm)/(24*3600) - diffTm; }
			else if(tpReq == 3) { lastResTm = rdResTime; leftResTm = (SYS.time()-lastResTm)/(31*24*3600); }
		}
	}
}

if(t_err.length) {
	SYS.messDebug("/VKT7/TMPL",tr("Error response")+": "+t_err);
	f_err = t_err;
	for(var cA in varsLs) arguments[cA] = EVAL_REAL;
}
else f_err = errAttrs.length ? "11:"+tr("Quality errors")+": "+errAttrs : "0";


ID: SMDP
NAME: Sycon Multi Drop Protocol
DESCR:
STM devices for resonant frequency measurement for mass of deposited films attached to their surface by Sycon Instruments, Inc. (http://www.sycon.com).

Author: Roman Savochenko <roman@oscada.org>
Sponsored: Vasiliy Grigoriev from "Vacuum technologies laboratory (http://e-beam.ru)".
Version: 1.0.0
License: GPLv2

PROGRAM:
JavaLikeCalc.JavaScript
if(f_stop) return;
if(f_start) {
	cnt = 0;
	version = "";
	SessId_ = SessId = QlvlTrip_ = QlvlTrip = SlvlTrip_ = SlvlTrip = EVAL_INT;
	Fq_ = Fq = Fm_ = Fm = Density_ = Density = Zratio_ = Zratio = Tooling_ = Tooling = RateReq_ = RateReq = EVAL_REAL;
}

tr = SYS.Transport.Serial.nodeAt("out_"+transport);
req = SYS.XMLNode("mess").setAttr("ProtIt","SMDP").setAttr("addr",addr).setAttr("try",3);

t_err = "";

//Configurations first write
// Session ID.
if(SessId != SessId_) {
	SYS.messDebug("/SMDP/tmpl",""+SessId+"!="+SessId_);	
	req.setAttr("err","1:"+tr("No connect")).setText("\xD0\x41"+SessId); tr.messIO(req,"UserProtocol");
	if(!(t_err=req.attr("err")).length) SessId_ = SessId; else SessId = SessId_;
}
// Xtal start freq. (Hz)
if(Fq != Fq_) {
	req.setAttr("err","1:"+tr("No connect")).setText("\xD0\x42"+Fq); tr.messIO(req,"UserProtocol");
	if(!(t_err=req.attr("err")).length) Fq_ = Fq; else Fq = Fq_;
}
// Xtal min freq. (Hz)
if(Fm != Fm_) {
	req.setAttr("err","1:"+tr("No connect")).setText("\xD0\x43"+Fm); tr.messIO(req,"UserProtocol");
	if(!(t_err=req.attr("err")).length) Fm_ = Fm; else Fm = Fm_;
}
// Material density (gm/cc).
if(Density != Density_) {
	req.setAttr("err","1:"+tr("No connect")).setText("\xD0\x44"+Density); tr.messIO(req,"UserProtocol");
	if(!(t_err=req.attr("err")).length) Density_ = Density; else Density = Density_;
}
// Material Z ratio. Not scaled or unitized.
if(Zratio != Zratio_) {
	req.setAttr("err","1:"+tr("No connect")).setText("\xD0\x45"+Zratio); tr.messIO(req,"UserProtocol");
	if(!(t_err=req.attr("err")).length) Zratio_ = Zratio; else Zratio = Zratio_;
}
// 1.000 is 100 % tooling (unity).
if(Tooling != Tooling_) {
	req.setAttr("err","1:"+tr("No connect")).setText("\xD0\x46"+Tooling); tr.messIO(req,"UserProtocol");
	if(!(t_err=req.attr("err")).length) Tooling_ = Tooling; else Tooling = Tooling_;
}
// Requested rate (A/S).
if(RateReq != RateReq_) {
	req.setAttr("err","1:"+tr("No connect")).setText("\xD0\x47"+RateReq); tr.messIO(req,"UserProtocol");
	if(!(t_err=req.attr("err")).length) RateReq_ = RateReq; else RateReq = RateReq_;
}
// Quality threshold, if non 0 and exceeded, xtal fail occurs.
if(QlvlTrip != QlvlTrip_) {
	req.setAttr("err","1:"+tr("No connect")).setText("\xD0\x48"+QlvlTrip); tr.messIO(req,"UserProtocol");
	if(!(t_err=req.attr("err")).length) QlvlTrip_ = QlvlTrip; else QlvlTrip = QlvlTrip_;
}
// Stability threshold, if non 0 and exceeded, xtal fail occurs.
if(SlvlTrip != SlvlTrip_) {
	req.setAttr("err","1:"+tr("No connect")).setText("\xD0\x49"+SlvlTrip); tr.messIO(req,"UserProtocol");
	if(!(t_err=req.attr("err")).length) SlvlTrip_ = SlvlTrip; else SlvlTrip = SlvlTrip_;
}

//======= Data getting (by self bigger period) ========
if((cnt++)%max(1,perGet*f_frq))	return;

//Configurations first read
// Session ID.
if(!t_err.length && SessId.isEVal()) {
	req.setAttr("err","1:"+tr("No connect")).setText("\xC0\x41"); tr.messIO(req,"UserProtocol");
	SessId = SessId_ = (t_err=req.attr("err")).length ? EVAL_INT : req.text().slice(2).toInt(10);
}
// Xtal start freq. (Hz)
if(!t_err.length && Fq.isEVal()) {
	req.setAttr("err","1:"+tr("No connect")).setText("\xC0\x42"); tr.messIO(req,"UserProtocol");
	Fq = Fq_ = (t_err=req.attr("err")).length ? EVAL_REAL : req.text().slice(2).toReal();
}
// Xtal min freq. (Hz)
if(!t_err.length && Fm.isEVal()) {
	req.setAttr("err","1:"+tr("No connect")).setText("\xC0\x43"); tr.messIO(req,"UserProtocol");
	Fm = Fm_ = (t_err=req.attr("err")).length ? EVAL_REAL : req.text().slice(2).toReal();
}
// Material density (gm/cc).
if(!t_err.length && Density.isEVal()) {
	req.setAttr("err","1:"+tr("No connect")).setText("\xC0\x44"); tr.messIO(req,"UserProtocol");
	Density = Density_ = (t_err=req.attr("err")).length ? EVAL_REAL : req.text().slice(2).toReal();
}
// Material Z ratio. Not scaled or unitized.
if(!t_err.length && Zratio.isEVal()) {
	req.setAttr("err","1:"+tr("No connect")).setText("\xC0\x45"); tr.messIO(req,"UserProtocol");
	Zratio = Zratio_ = (t_err=req.attr("err")).length ? EVAL_REAL : req.text().slice(2).toReal();
}
// 1.000 is 100 % tooling (unity).
if(!t_err.length && Tooling.isEVal()) {
	req.setAttr("err","1:"+tr("No connect")).setText("\xC0\x46"); tr.messIO(req,"UserProtocol");
	Tooling = Tooling_ = (t_err=req.attr("err")).length ? EVAL_REAL : req.text().slice(2).toReal();
}
// Requested rate (A/S).
if(!t_err.length && RateReq.isEVal()) {
	req.setAttr("err","1:"+tr("No connect")).setText("\xC0\x47"); tr.messIO(req,"UserProtocol");
	RateReq = RateReq_ = (t_err=req.attr("err")).length ? EVAL_REAL : req.text().slice(2).toReal();
}
// Quality threshold, if non 0 and exceeded, xtal fail occurs.
if(!t_err.length && QlvlTrip.isEVal()) {
	req.setAttr("err","1:"+tr("No connect")).setText("\xC0\x48"); tr.messIO(req,"UserProtocol");
	QlvlTrip = QlvlTrip_ = (t_err=req.attr("err")).length ? EVAL_REAL : req.text().slice(2).toInt(10);
}
// Stability threshold, if non 0 and exceeded, xtal fail occurs.
if(!t_err.length && SlvlTrip.isEVal()) {
	req.setAttr("err","1:"+tr("No connect")).setText("\xC0\x49"); tr.messIO(req,"UserProtocol");
	SlvlTrip = SlvlTrip_ = (t_err=req.attr("err")).length ? EVAL_REAL : req.text().slice(2).toInt(10);
}

//Runtime variables
// Read version, single
if(!t_err.length && (!version.length || version.isEVal())) {
	req.setAttr("err","1:"+tr("No connect")).setText("\x40"); tr.messIO(req,"UserProtocol");
	version = (t_err=req.attr("err")).length ? EVAL_STR : req.text().slice(1);
}

// Read Configuration parameter session ID
if(t_err.length) CfgPrmSSID = EVAL_INT;
else {
	req.setAttr("err","1:"+tr("No connect")).setText("\xC0\x61"); tr.messIO(req,"UserProtocol");
	CfgPrmSSID = (t_err=req.attr("err")).length ? EVAL_INT : req.text().slice(2).toInt(10);
	//SYS.messDebug("/SMDP/tmpl","CfgPrmSSID: "+req.text());
}

// Read Measurement serial number
if(t_err.length) Srlno = EVAL_INT;
else {
	req.setAttr("err","1:"+tr("No connect")).setText("\xC0\x62"); tr.messIO(req,"UserProtocol");
	Srlno = (t_err=req.attr("err")).length ? EVAL_INT : req.text().slice(2).toInt(10);
}

// Read Channel freq.
if(t_err.length) RawFreq = EVAL_REAL;
else {
	req.setAttr("err","1:"+tr("No connect")).setText("\xC0\x63"); tr.messIO(req,"UserProtocol");
	RawFreq = (t_err=req.attr("err")).length ? EVAL_REAL : req.text().slice(2).toReal();
}

// Read Last used, good channel freq. (Hz)
if(t_err.length) GoodFreq = EVAL_REAL;
else {
	req.setAttr("err","1:"+tr("No connect")).setText("\xC0\x64"); tr.messIO(req,"UserProtocol");
	GoodFreq = (t_err=req.attr("err")).length ? EVAL_REAL : req.text().slice(2).toReal();
}

// Read Computed raw thickness, from frequency. (A)
if(t_err.length) RawThick = EVAL_REAL;
else {
	req.setAttr("err","1:"+tr("No connect")).setText("\xC0\x65"); tr.messIO(req,"UserProtocol");
	RawThick = (t_err=req.attr("err")).length ? EVAL_REAL : req.text().slice(2).toReal();
}

// Read Computed material related thickness, can be zeroed. (A)
if(t_err.length) XtalThick = EVAL_REAL;
else {
	req.setAttr("err","1:"+tr("No connect")).setText("\xC0\x66"); tr.messIO(req,"UserProtocol");
	XtalThick = (t_err=req.attr("err")).length ? EVAL_REAL : req.text().slice(2).toReal();
}

// Read Filtered computed material related thickness, can be zeroed. (A)
if(t_err.length) XtalThick_F = EVAL_REAL;
else {
	req.setAttr("err","1:"+tr("No connect")).setText("\xC0\x67"); tr.messIO(req,"UserProtocol");
	XtalThick_F = (t_err=req.attr("err")).length ? EVAL_REAL : req.text().slice(2).toReal();
}

// Read Rate, angstroms per second.
if(t_err.length) XtalRate = EVAL_REAL;
else {
	req.setAttr("err","1:"+tr("No connect")).setText("\xC0\x68"); tr.messIO(req,"UserProtocol");
	XtalRate = (t_err=req.attr("err")).length ? EVAL_REAL : req.text().slice(2).toReal();
}

// Read Rate, angstroms per second, filtered.
if(t_err.length) XtalRate_F = EVAL_REAL;
else {
	req.setAttr("err","1:"+tr("No connect")).setText("\xC0\x69"); tr.messIO(req,"UserProtocol");
	XtalRate_F = (t_err=req.attr("err")).length ? EVAL_REAL : req.text().slice(2).toReal();
}

// Read XtalLife (%)
if(t_err.length) XtalLife = EVAL_REAL;
else {
	req.setAttr("err","1:"+tr("No connect")).setText("\xC0\x6A"); tr.messIO(req,"UserProtocol");
	XtalLife = (t_err=req.attr("err")).length ? EVAL_REAL : req.text().slice(2).toReal();
}

// Read Quality level (0-9).
if(t_err.length) XtalQual = EVAL_INT;
else {
	req.setAttr("err","1:"+tr("No connect")).setText("\xC0\x6B"); tr.messIO(req,"UserProtocol");
	XtalQual = (t_err=req.attr("err")).length ? EVAL_INT : req.text().slice(2).toInt(10);
}

// Read Highest quality level seen (0-9).
if(t_err.length) XtalQualPeak = EVAL_INT;
else {
	req.setAttr("err","1:"+tr("No connect")).setText("\xC0\x6C"); tr.messIO(req,"UserProtocol");
	XtalQualPeak = (t_err=req.attr("err")).length ? EVAL_INT : req.text().slice(2).toInt(10);
}

// Read Stability level (0-9).
if(t_err.length) XtalStab = EVAL_INT;
else {
	req.setAttr("err","1:"+tr("No connect")).setText("\xC0\x6D"); tr.messIO(req,"UserProtocol");
	XtalStab = (t_err=req.attr("err")).length ? EVAL_INT : req.text().slice(2).toInt(10);
}

// Read Highest stability level seen (0-9).
if(t_err.length) XtalStabPeak = EVAL_INT;
else {
	req.setAttr("err","1:"+tr("No connect")).setText("\xC0\x6E"); tr.messIO(req,"UserProtocol");
	XtalStabPeak = (t_err=req.attr("err")).length ? EVAL_INT : req.text().slice(2).toInt(10);
}

// Read Channel status.
if(t_err.length) XtalStat = EVAL_STR;
else {
	req.setAttr("err","1:"+tr("No connect")).setText("\xC0\x6F"); tr.messIO(req,"UserProtocol");
	if((t_err=req.attr("err")).length) XtalStat = EVAL_STR;
	else {
		stCd = req.text().slice(2).toInt(10);
		stLab = tr("Unknown");
		if(stCd == 0)			stLab = "XPROB_NONE: "+tr("No Problems. The rest below are prioritized.");
		else if(stCd == 1)	stLab = "XPROB_FREQ: "+tr("Frequency of xtal is > Fq or < Fm. Halts all other calculations.");
		else if(stCd == 2)	stLab = "XPROB_LOWLIFE: "+tr("Frequency was bad (previous XtalStat was XPROB_FREQ) and frequency is now in range, but life is less than 3%.");
		else if(stCd == 3)	stLab = "XPROB_S_FAIL: "+tr("Stability level XtalStab of xtal >= SlvlTrip.");
		else if(stCd == 4)	stLab = "XPROB_MATH: "+tr("Unable to determine rate because of a computation error, most likely caused by a parameter (density, z-ratio, etc) having a zero or otherwise invalid (non numeric or infinity) value.");
		else if(stCd == 5)	stLab = "XPROB_Q_FAIL: "+tr("XtalQual of xtal >= QlvlTrip.");
		XtalStat = ""+stCd+":"+stLab;
	}
}

// Read XtalLife (%).
if(t_err.length) XtalLife_C = EVAL_INT;
else {
	req.setAttr("err","1:"+tr("No connect")).setText("\xC0\x70"); tr.messIO(req,"UserProtocol");
	XtalLife_C = (t_err=req.attr("err")).length ? EVAL_INT : req.text().slice(2).toInt(10);
}

f_err = t_err.length ? t_err : "0";


ID: IT3
NAME: Temperature measurement IT-3
DESCR:
Temperature measurement IT-3 from OmskEtalon (http://www.omsketalon.ru).

Author: Roman Savochenko <roman@oscada.org>
Sponsored: Vasiliy Grigoriev from "Vacuum technologies laboratory (http://e-beam.ru)".
Version: 1.2.0
License: GPLv2

PROGRAM:
JavaLikeCalc.JavaScript
if(mdPass)	{
	if(f_start) { f_err = EVAL; this.cnt.set(0, 0, 0, true); cnt_ = 0; tDl = 5; }
	if((cnt=this.cnt.get()) != cnt_)	{ tDl = 5; cnt_ = cnt; }
	else if(tDl > 0 && (tDl=tDl-1/f_frq) <= 0) {
		this.err.set("1:"+tr("No data"), 0, 0, true);
		this.T.set(EVAL, 0, 0, true);
		this.H.set(EVAL, 0, 0, true);
		this.L.set(EVAL, 0, 0, true);
		this.relSt.set(EVAL, 0, 0, true);
	}
	return;
}

//Set transport
if(f_start)	tr = SYS.Transport.Serial.nodeAt("out_"+transport);
if(!tr)	t_err = "1:"+tr("Serial output transport '%1' error.").replace("%1",transport);

req = SYS.XMLNode("mess").setAttr("ProtIt","IT3").setAttr("addr",addr);

SYS.messDebug("/IT3/TMPL",tr("Request: TRANSL_TEMP."));
req.setAttr("err","2:"+tr("No connection")).setText(SYS.strFromCharCode(0xC3));
tr.messIO(req, "UserProtocol");
if(!(t_err=req.attr("err")).length && req.text().charCodeAt(0) == 0x85) {
	cntrB = req.text().charCodeAt(3);
	T = (req.text().charCodeAt(2)<<8)+req.text().charCodeAt(1);
	T = T/((cntrB&0x8)?100:10);
	relSt = (cntrB&0x1);
	L = (cntrB&0x2);
	H = (cntrB&0x4);
	//SYS.messDebug("/IT3/TMPL",tr("Request: TRANSL_TEMP: "+req.text().length));
}
else {
	T = H = L = EVAL_STR;
	if(t_err.parse(1,":").toInt() == 8) {
		req.setAttr("err","2:"+tr("No connection")).setText(SYS.strFromCharCode(0x00));
		tr.messIO(req, "UserProtocol");
	}
}

if(t_err.length) { SYS.messDebug("/IT3/TMPL",tr("Error response")+": "+t_err); f_err = t_err; }
else f_err = "0";


ID: IVE_452HS_02
NAME: IVE-452HS-02
DESCR:
Power supply of beam-electrons evaporator of "Plasma Tech" Ltd, from Moskov.

Author: Roman Savochenko <roman@oscada.org>
Sponsored: Vasiliy Grigoriev from "Vacuum technologies laboratory (http://e-beam.ru)".
Version: 1.0.0
License: GPLv2

PROGRAM:
JavaLikeCalc.JavaScript
//Set transport
if(f_start) {
	addr_ = addr;
	transport_ = transport;
	COIA = COIA_ = COUA = COUA_ = COPA = COPA_ = DIA = DUA = DPA = DFA = EVAL_INT;
	COM_DEW = COM_DEW_ = COM_OUT = COM_OUT_ = COM_DEP	= COM_DEP_ = COM_DEL = COM_DEL_ = COM_UF = COM_UF_ =
					DKW = DKZ = DK = DE = EVAL_BOOL;
	tr = SYS.Transport.nodeAt(transport,".");
}

//Check for the transport change and connect
if(!tr || transport != transport_)	{
	tr = SYS.Transport.nodeAt(transport,".");
	transport_ = transport;
}
if(!tr)	t_err = "1:"+tr("Output transport '%1' error.").replace("%1",transport);
else {
	req = SYS.XMLNode("mess").setAttr("ProtIt","IVE_452HS_02").setAttr("addr",addr);

	//Check for the address need to change
	if(addr != addr_) {
		hwReg = 0x00;
		req.setAttr("err","2:"+tr("No connection")).setAttr("addr",addr_)
			.setText(SYS.strFromCharCode(0x57,0x04,0x00,hwReg,hwReg,0x06,addr));
		tr.messIO(req, "UserProtocol");
		req.setText(SYS.strFromCharCode(0x57,0x04,0x00,hwReg,hwReg,0x08,0x00));
		tr.messIO(req, "UserProtocol");
		req.setAttr("addr", addr);
		addr_ = addr;
	}

	//Check and write commands
	if(COIA != COIA_ && !(t_err=req.attr("err")).length)	{
		hwReg = 0x01;
		req.setAttr("err","2:"+tr("No connection")).setText(SYS.strFromCharCode(0x57,0x04,0x00,hwReg,hwReg,COIA&0xFF,(COIA>>8)&0xFF));
		tr.messIO(req, "UserProtocol");
	}
	if(COUA != COUA_ && !(t_err=req.attr("err")).length) {
		hwReg = 0x02;
		req.setAttr("err","2:"+tr("No connection")).setText(SYS.strFromCharCode(0x57,0x04,0x00,hwReg,hwReg,COUA&0xFF,(COUA>>8)&0xFF));
		tr.messIO(req, "UserProtocol");
	}
	if(COPA != COPA_ && !(t_err=req.attr("err")).length) {
		hwReg = 0x03;
		req.setAttr("err","2:"+tr("No connection")).setText(SYS.strFromCharCode(0x57,0x04,0x00,hwReg,hwReg,COPA&0xFF,(COPA>>8)&0xFF));
		tr.messIO(req, "UserProtocol");
	}
	if((COM_DEW != COM_DEW_ || COM_OUT != COM_OUT_ || COM_DEP != COM_DEP_ || COM_DEL != COM_DEL_ || COM_UF != COM_UF_) && !(t_err=req.attr("err")).length) {
		tmp = 0;
		if(COM_DEW)	tmp = tmp | 0x8000;
		if(COM_OUT)	tmp = tmp | 0x4000;
		if(COM_DEP)	tmp = tmp | 0x1000;
		if(COM_DEL)	tmp = tmp | 0x0800;
		if(COM_UF)	tmp = tmp | 0x0004;
		hwReg = 0x15;
		req.setAttr("err","2:"+tr("No connection")).setText(SYS.strFromCharCode(0x57,0x04,0x00,hwReg,hwReg,tmp&0xFF,(tmp>>8)&0xFF));
		tr.messIO(req, "UserProtocol");
	}

	//Read data
	if(!(t_err=req.attr("err")).length) {
		SYS.messDebug("/IVE452HS02/TMPL",tr("Read all data."));
		req.setAttr("err","2:"+tr("No connection")).setText(SYS.strFromCharCode(0x52,0x02,0x00,0x01,0x16));
		tr.messIO(req, "UserProtocol");
		if(!(t_err=req.attr("err")).length) {
			if(req.text().length < (0x16*2+5))	req.setAttr("err", "10:"+tr("Reply is not full"));
			else {
				hwReg = 0x01; COIA = COIA_ = (req.text().charCodeAt((hwReg-1)*2+6)<<8)+req.text().charCodeAt((hwReg-1)*2+5);
				hwReg = 0x02; COUA = COUA_ = (req.text().charCodeAt((hwReg-1)*2+6)<<8)+req.text().charCodeAt((hwReg-1)*2+5);
				hwReg = 0x03; COPA = COPA_ = (req.text().charCodeAt((hwReg-1)*2+6)<<8)+req.text().charCodeAt((hwReg-1)*2+5);
				hwReg = 0x07; DIA = (req.text().charCodeAt((hwReg-1)*2+6)<<8)+req.text().charCodeAt((hwReg-1)*2+5);
				hwReg = 0x08; DUA = (req.text().charCodeAt((hwReg-1)*2+6)<<8)+req.text().charCodeAt((hwReg-1)*2+5);
				hwReg = 0x0E; DAC = (req.text().charCodeAt((hwReg-1)*2+6)<<8)+req.text().charCodeAt((hwReg-1)*2+5);
				hwReg = 0x10; DPA = (req.text().charCodeAt((hwReg-1)*2+6)<<8)+req.text().charCodeAt((hwReg-1)*2+5);
				hwReg = 0x11; DFA = (req.text().charCodeAt((hwReg-1)*2+6)<<8)+req.text().charCodeAt((hwReg-1)*2+5);
				hwReg = 0x15; tmp = (req.text().charCodeAt((hwReg-1)*2+6)<<8)+req.text().charCodeAt((hwReg-1)*2+5);
				COM_DEW = COM_DEW_ = tmp&0x8000;
				COM_OUT = COM_OUT_ = tmp&0x4000;
				COM_DEP = COM_DEP_ = tmp&0x1000;
				COM_DEL = COM_DEL_ = tmp&0x0800;
				COM_UF = COM_UF_ = tmp&0x0004;
				hwReg = 0x16; tmp = (req.text().charCodeAt((hwReg-1)*2+6)<<8)+req.text().charCodeAt((hwReg-1)*2+5);
				DKW = !(tmp&0x8); DKZ = !(tmp&0x4); DK = !(tmp&0x2); DE = tmp&0x1;
			}
		}
	}
}

if(t_err.length) {
	COIA = COIA_ = COUA = COUA_ = COPA = COPA_ = DIA = DUA = DAC = DPA = DFA = EVAL_INT;
	COM_DEW = COM_DEW_ = COM_OUT = COM_OUT_ = COM_DEP	= COM_DEP_ = COM_DEL = COM_DEL_ = COM_UF = COM_UF_ = 
					DKW = DKZ = DK = DE = EVAL_BOOL;
	SYS.messDebug("/IVE452HS02/TMPL",tr("Error response")+": "+t_err);
	f_err = t_err;
}
else f_err = "0";


ID: OPTRIS
NAME: OPTRIS CT/CTL
DESCR:
OPTRIS CT/CTL communication interface of "Optris" GmbH, from Berlin.

Author: Roman Savochenko <roman@oscada.org>
Sponsored: Vasiliy Grigoriev from "Vacuum technologies laboratory (http://e-beam.ru)".
Version: 1.0.0
License: GPLv2

PROGRAM:
JavaLikeCalc.JavaScript
//Set transport
if(f_start) {
	transport_ = transport;
	Tproc = Thead = Tbox = Tact = eps = eps_ = trans = trans_ = EVAL_REAL;
	spIll = spIll_ = EVAL_BOOL;
	tr = SYS.Transport.nodeAt(transport, ".");
}

//Check for the transport change and connect
if(!tr || transport != transport_)	{
	tr = SYS.Transport.nodeAt(transport, ".");
	transport_ = transport;
}
if(!tr)	t_err = "1:"+tr("Output transport '%1' error.").replace("%1",transport);
else {
	req = SYS.XMLNode("mess").setAttr("ProtIt", "OPTRIS").setAttr("addr", addr).setAttr("cs", "1");

	//Check and write
	// Epsilon
	if(eps != eps_ && !(t_err=req.attr("err")).length) {
		epsH = eps*1000;
		req.setAttr("err","2:"+tr("No connection")).setText(SYS.strFromCharCode(0x84,epsH/256,epsH%256));
		tr.messIO(req, "UserProtocol");
	}
	// Transmission
	if(trans != trans_ && !(t_err=req.attr("err")).length) {
		transH = trans*1000;
		req.setAttr("err","2:"+tr("No connection")).setText(SYS.strFromCharCode(0x85,transH/256,transH%256));
		tr.messIO(req, "UserProtocol");
	}
	// Spot illumination
	if(spIll != spIll_ && !(t_err=req.attr("err")).length) {
		req.setAttr("err","2:"+tr("No connection")).setText(SYS.strFromCharCode(0xA5,spIll));
		tr.messIO(req, "UserProtocol");
	}

	//Read data
	req.setAttr("cs", "0");
	// Tproc
	if(!(t_err=req.attr("err")).length) {
		req.setAttr("err","2:"+tr("No connection")).setText(SYS.strFromCharCode(0x01));
		tr.messIO(req, "UserProtocol");
		Tproc = (!(t_err=req.attr("err")).length && req.text().length >= 2) ? (req.text().charCodeAt(0)*256+req.text().charCodeAt(1)-1000)/10 : EVAL_REAL;
	}
	// Thead
	if(!(t_err=req.attr("err")).length) {
		req.setAttr("err","2:"+tr("No connection")).setText(SYS.strFromCharCode(0x02));
		tr.messIO(req, "UserProtocol");
		Thead = (!(t_err=req.attr("err")).length && req.text().length >= 2) ? (req.text().charCodeAt(0)*256+req.text().charCodeAt(1)-1000)/10 : EVAL_REAL;
	}
	// Tbox
	if(!(t_err=req.attr("err")).length) {
		req.setAttr("err","2:"+tr("No connection")).setText(SYS.strFromCharCode(0x03));
		tr.messIO(req, "UserProtocol");
		Tbox = (!(t_err=req.attr("err")).length && req.text().length >= 2) ? (req.text().charCodeAt(0)*256+req.text().charCodeAt(1)-1000)/10 : EVAL_REAL;
	}
	// Tact
	if(!(t_err=req.attr("err")).length) {
		req.setAttr("err","2:"+tr("No connection")).setText(SYS.strFromCharCode(0x81));
		tr.messIO(req, "UserProtocol");
		Tact = (!(t_err=req.attr("err")).length && req.text().length >= 2) ? (req.text().charCodeAt(0)*256+req.text().charCodeAt(1)-1000)/10 : EVAL_REAL;
	}
	// IR epsilon
	if(!(t_err=req.attr("err")).length) {
		req.setAttr("err","2:"+tr("No connection")).setText(SYS.strFromCharCode(0x04));
		tr.messIO(req, "UserProtocol");
		eps = eps_ = (!(t_err=req.attr("err")).length && req.text().length >= 2) ? (req.text().charCodeAt(0)*256+req.text().charCodeAt(1))/1000 : EVAL_REAL;
	}
	// IR transmission
	if(!(t_err=req.attr("err")).length) {
		req.setAttr("err","2:"+tr("No connection")).setText(SYS.strFromCharCode(0x05));
		tr.messIO(req, "UserProtocol");
		trans = trans_ = (!(t_err=req.attr("err")).length && req.text().length >= 2) ? (req.text().charCodeAt(0)*256+req.text().charCodeAt(1))/1000 : EVAL_REAL;
	}
	// Spot illumination
	if(!(t_err=req.attr("err")).length) {
		req.setAttr("err","2:"+tr("No connection")).setText(SYS.strFromCharCode(0x25));
		tr.messIO(req, "UserProtocol");
		spIll = spIll_ = (!(t_err=req.attr("err")).length && req.text().length >= 1) ? req.text().charCodeAt(0) : EVAL_BOOL;
	}
}

//Error set
if(t_err.length) {
	Tproc = Thead = Tbox = Tact = eps = eps_ = trans = trans_ = spIll = spIll_ = EVAL_REAL;
	spIll = spIll_ = EVAL_BOOL;
	SYS.messDebug("/OPTRIS/TMPL",tr("Error response")+": "+t_err);
	f_err = t_err;
}
else f_err = "0";


ID: CTR
NAME: CTR 100, 101
DESCR:
The RS232C Serial Interface permits the communication between the digital Oerlikon Leybold Vacuum CERAVAC, from Köln.

Author: Roman Savochenko <roman@oscada.org>
Sponsored: Vasiliy Grigoriev from "Vacuum technologies laboratory (http://e-beam.ru)".
Version: 1.0.0
License: GPLv2

PROGRAM:
JavaLikeCalc.JavaScript
//Set transport
if(f_start) {
	transport_ = transport;
	press = FSR_Mantissa = FSR_Exp = EVAL_REAL;
	tr = SYS.Transport.nodeAt(transport, ".");
}

u_err = "";

//Check for the transport change and connect
if(!tr || transport != transport_)	{
	tr = SYS.Transport.nodeAt(transport, ".");
	transport_ = transport;
}
if(!tr)	t_err = "1:"+tr("Output transport '%1' error.").replace("%1",transport);
else {
	req = SYS.XMLNode("mess").setAttr("ProtIt","CTR");

	//Read data
	// F.S.R Mantisa
	if(!(t_err=req.attr("err")).length && FSR_Mantissa.isEVal()) {
		req.setAttr("err","2:"+tr("No connection")).setText(SYS.strFromCharCode(0x00,0x39,0x00));
		tr.messIO(req, "UserProtocol");
		if(!(t_err=req.attr("err")).length) {
			if((cV=req.text().charCodeAt(5)) == 0) FSR_Mantissa = 1.0;
			else if(cV == 1) FSR_Mantissa = 1.1;
			else if(cV == 2) FSR_Mantissa = 2.0;
			else if(cV == 3) FSR_Mantissa = 2.5;
			else if(cV == 4) FSR_Mantissa = 5.0;
		}
	}
	// F.S.R Exp
	if(!(t_err=req.attr("err")).length && FSR_Exp.isEVal()) {
		req.setAttr("err","2:"+tr("No connection")).setText(SYS.strFromCharCode(0x00,0x38,0x00));
		tr.messIO(req, "UserProtocol");
		if(!(t_err=req.attr("err")).length) {
			if((cV=req.text().charCodeAt(5)) == 2) FSR_Exp = -1;
			else if(cV == 3) FSR_Exp = 0;
			else if(cV == 4) FSR_Exp = 1;
			else if(cV == 5) FSR_Exp = 2;
			else if(cV == 6) FSR_Exp = 3;
		}
	}
	// Main value
	if(!(t_err=req.attr("err")).length && !FSR_Mantissa.isEVal() && !FSR_Exp.isEVal()) {
		req.setAttr("err","2:"+tr("No connection")).setText(SYS.strFromCharCode(0x00,0x00,0x00));
		tr.messIO(req, "UserProtocol");
		if(!(t_err=req.attr("err")).length) {
			press = ((req.text().charCodeAt(3)*256+req.text().charCodeAt(4))/32000)*FSR_Mantissa*pow(10,FSR_Exp);
			//  Error process
			cV = req.text().charCodeAt(2);
			if(cV&0x7F) {
				if(cV&0x01)	u_err += tr("RS232 synchronization error. ");
				if(cV&0x02)	u_err += tr("Incorrect command, e.g. inadmissible address (syntax error). ");
				if(cV&0x04)	u_err += tr("Inadmissible read command. ");
				if(cV&0x08)	u_err += tr("SP1 status. ");
				if(cV&0x10)	u_err += tr("SP2 status. ");
			}
			else {
				//   Extended Error L-Byte
				req.setAttr("err","2:"+tr("No connection")).setText(SYS.strFromCharCode(0x00,0x36,0x00));
				tr.messIO(req, "UserProtocol");
				if(!(t_err=req.attr("err")).length) {
					cV = req.text().charCodeAt(5);
					if(cV&0x01)	u_err += tr("Atm. pressure out of range. ");
					if(cV&0x02)	u_err += tr("Temperature out of range. ");
					if(cV&0x10)	u_err += tr("Cal. mode wrong. ");
					if(cV&0x20)	u_err += tr("Pressure underflow. ");
					if(cV&0x40)	u_err += tr("Pressure overflow. ");
					if(cV&0x80)	u_err += tr("Zero adjust warning. ");
				}
				//   Extended Error H-Byte
				req.setAttr("err","2:"+tr("No connection")).setText(SYS.strFromCharCode(0x00,0x37,0x00));
				tr.messIO(req, "UserProtocol");
				cV = req.text().charCodeAt(5);
				if(cV&0x01)	u_err += tr("PT1000 fault (CTR 101 only). ");
				if(cV&0x02)	u_err += tr("Heaterblock overtemp. ");
				if(cV&0x04)	u_err += tr("Electronic overtemp. ");
				if(cV&0x08)	u_err += tr("Zero adjust error. ");
			}
		}
	}

	//Check and write commands
	// Zero-adjust
	if(!(t_err=req.attr("err")).length && zeroSet) {
		req.setAttr("err", "2:"+tr("No connection")).setText(SYS.strFromCharCode(0x40,0x02,0x00));
		tr.messIO(req, "UserProtocol");
		if(!(t_err=req.attr("err")).length) zeroSet = false;
	}

	//Check and set poll mode
	if((t_err=req.attr("err")).length && t_err.toInt() == 4) {
		req.setAttr("err", "2:"+tr("No connection")).setText(SYS.strFromCharCode(0x10,0x00,0x01));
		tr.messIO(req, "UserProtocol");
	}
}

if(t_err.length) {
	press = EVAL_REAL;
	f_err = t_err + " " + u_err;
}
else f_err = "0: " + u_err;


ID: IEC60870
NAME: IEC-60870
uk#NAME: IEC-60870
DESCR:
IEC 60870 part 5 is one from the IEC 60870 set of standards which defines systems used for telecontrol (supervisory control and data acquisition) in electrical engineering and power system automation applications. Part 5 provides a communication profile for sending basic telecontrol messages between two systems, which uses permanent directly connected data circuits between the systems.

The template currently implements the part 104 (Ethernet transport) for the client and followed services: STARTDT, STOPDT, TESTFR, Ack, C_IC_NA_1 (100), C_CI_NA_1 (101), C_SC_NA_1 (45), M_SP_NA_1 (1), M_SP_TA_1 (2), M_DP_NA_1 (3), M_DP_TA_1 (4), M_ME_NB_1 (11), M_ME_NC_1 (13), M_ME_TF_1 (36), C_CS_NA_1 (103). For information ones, the sequential (SQ) mode enabling and disabling are supported.

For the direct definition of the requested data, the "itemsSet" attribute is provided, where they can be defined individually, with a semantic identifier and name, or in a range named by a template. Often, remote systems may not need to determine the data to transmit and send existing or generic ones on their own initiative, and if they do not, have and need to ask for something additional ones, then you need to get a map of the available parameters with the addresses these you enter in this attribute in the format ai|di|do:{IOA}[-{EndIOA}][:a[:{NameBase}]], where:
- ai|di|do — data type, where:
  - "ai" — analog inputs, transmitted by the message M_ME_NB_1, M_ME_NC_1, M_ME_TF_1 and requested by C_SC_NA_1;
  - "di" — discrete inputs, transmitted by the message M_SP_NA_1, M_SP_TA_1, M_DP_NA_1, M_DP_TA_1 and requested by C_SC_NA_1;
  - "do" — discrete outputs, transmitted by C_SC_NA_1.
- {IOA} — parameter address of the range begin;
- {EndIOA} — the range end (the last item address);
- a — sign of creating the representative attribute for the parameter or the parameters group;
- {NameBase} — naming base of the attributes.

Examples of the parameters definition, rows of the attribute "itemsSet":
- di:100-108:a — discrete inputs in the address range [100...108] with forming the attributes;
- ai:873-880:a — analog inputs in the address range [873...880] with forming the attributes;
- do:1-10:a — discrete outputs in the address range [1...10] with forming the attributes.

An object into the attribute "items" is used to accumulate the gathered and controlling data, to next control as an object with the data represent in a table of the widget "Main.objProps", alarming and allowing to set the writable attributes.

The module provides integrated support for time synchronization of PLC by sending the C_CS_NA_1 service command.

In the template for the first time used the not requesting mode of an output transport and the attributes creation in free while performing.

Author: Roman Savochenko <roman@oscada.org>
Total complexity: 3.8 HD
Sponsored by: Ustijancev Michael for 3.0 HD, SVItoVYR Ltd for 0.8 HD
Version: 1.4.0
License: GPLv2

uk#DESCR:
IEC 60870 у частині 5 є одним з набору стандартів IEC 60870 який визначає системи, що використовуються у віддаленому контролі (телемеханіці — диспетчерському контролі та зборі даних) у інженерній електриці та у застосунках автоматизації енергетичних систем. Частина 5 надає комунікаційний профіль для надсилання базових повідомлень віддаленого контролю між двома системами, який використовує постійні прямі підключення даних між системами.

Шаблон наразі реалізує частину 104 (Ethernet транспорт) для клієнту та наступних сервісів: STARTDT, STOPDT, TESTFR, Ack, C_IC_NA_1 (100), C_CI_NA_1 (101), C_SC_NA_1 (45), M_SP_NA_1 (1), M_ME_NB_1 (11), M_ME_NC_1 (13), M_ME_TF_1 (36), C_CS_NA_1 (103). Для інформаційних сервісів підтримується ввімкнення та вимкнення послідовного (SQ) режиму.

Для прямого визначення запитуваних даних передбачено атрибут "itemsSet", де вони можуть визначатися як окремо, зі смисловим ідентифікатором та назвою, або за діапазоном із найменуванням по шаблону. Часто віддалені системи можуть не потребувати визначення даних для передачі та надсилають наявні або основні зі своєї ініціативи та якщо вони цього не роблять, мають та потрібно запитати щось додаткове то вам треба отримати мапу наявних параметрів з адресами які й ввести у цьому атрибуті записами у форматі ai|di|do:{IOA}[-{EndIOA}][:a[:{NameBase}]], де:
- ai|di|do — тип даних, де:
  - "ai" — аналогові входи, передані повідомленням M_ME_NB_1, M_ME_NC_1, M_ME_TF_1 та запитані C_SC_NA_1;
  - "di" — дискретні входи, передані повідомленням M_SP_NA_1 та запитані C_SC_NA_1;
  - "do" — дискретні виходи, передавані командою C_SC_NA_1.
- {IOA} — адреса параметру або початок діапазону;
- {EndIOA} — кінець (адреса останнього елементу) діапазону;
- a — ознака створення репрезентативних атрибутів для параметру або групи параметрів;
- {NameBase} — база назви атрибуту(ів).

Приклади визначення параметрів, рядки атрибуту "itemsSet":
- di:100-108:a — дискретні входи за діапазоном адрес [100...108] із формуванням атрибутів;
- ai:873-880:a — аналогові входи за діапазоном адрес [873...880] із формуванням атрибутів;
- do:1-10:a — дискретні виходи за діапазоном адрес [1...10] із формуванням атрибутів.

Об'єкт у атрибуті "items" використовується для акумулювання зібраних та контрольованих даних задля подальшого контрою як об'єкт із представленням даних у таблиці віджету "Main.objProps", сигналізуючи та дозволяючи встановлювати записувані атрибути.

Модулем надається вбудована підтримка синхронізації часу ПЛК, надсиланням сервісної команди C_CS_NA_1.

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

Автор: Роман Савоченко <roman@oscada.org>
Загальна працемісткість: 3.8 ЛД
Спонсорування: Устьянцев Михайло на 3.0 ЛД, ТОВ "СВІТоВИР" на 0.8 ЛД
Версія: 1.3.1
Ліцензія: GPLv2

PROGRAM:
JavaLikeCalc.JavaScript
function getTm(iSq) {
	ttm_ms = iSq.charCodeAt(1)*256 + iSq.charCodeAt(0);
	ttm = SYS.mktime(ttm_ms/1000, iSq.charCodeAt(2)&0x3F, iSq.charCodeAt(3)&0x1F, iSq.charCodeAt(4)&0x1F, (iSq.charCodeAt(5)&0x0F)-1, 2000+(iSq.charCodeAt(6)&0x7F));
	return ttm + ttm_ms*1e-3;
}

function inVal(aId, aVal, SIQ, wr, itm) {
	if(!SIQ.isEVal() && (SIQ&0xF0)) aVal = EVAL;	else SIQ = 0;
	if(wr.isEVal())	wr = false;
	if(itm.isEVal())	itm = 0;
	if(items[aId].isEVal()) {
		items[aId] = itW = new Object();
		itW.descr = aId;
		itW.wr = wr; itW.alarm = 0;
	} else itW = items[aId];
	itW.val = aVal;
	itW.SIQ = SIQ;	//For a specific quality processing
	if((aO=this[aId])) {
		aO.set(aVal, 0, 0, true);
		if(itm && aO.arch())	aO.arch().setVal(1e6*itm, aVal);
		if(itW.wr) oAVals[aId] = aVal;
	}
}

if(f_start)	{
	transport_ = "", tr = false;
	itemsSet_ = "";
	tmRetr_ = tmRetr;
	t1_ = t1__ = t2_ = t3_ = w_ = 0;
	TESTFR_Act = false;
	STARTDT_act = STARTDT_con = false;
	bufIn = bufOut = "";
	cntTx = cntRx = 0;
	destAddr = addr.parse(0,".").toInt();
	destOA = addr.parse(1,".").toInt();
	//C_IC_NA_1_req = 0;
	C_IC_NA_1 = C_SC_NA_1 = 0;
	C_IC_NA_1con = C_CS_NA_1 = C_CS_NA_1con = C_CI_NA_1 = C_CI_NA_1con = false;
	items = new Object();
	oAVals = new Object();
	return;
}
if(f_stop && !STARTDT_con)	return;	//But at stop we must yet send STOPDT

//Items set changing process
if(itemsSet != itemsSet_) {
	for(off = 0; (iIt=itemsSet.parse(0,"\n",off)).length; ) {
		iIt_tp = iIt.parse(0, ":");
		iIt_IOA = iIt.parse(1, ":");
		iIt_flgs = iIt.parse(2, ":");
		iIt_nmBase = iIt.parse(3, ":");
		iIt_sDscr = false;
		if((iIt_EndIOA=iIt_IOA.indexOf("-")) >= 0) {
			iIt_EndIOA = iIt_IOA.slice(iIt_EndIOA+1).toInt(0);
			iIt_IOA = iIt_IOA.slice(0,iIt_EndIOA).toInt(0);
		}
		else { iIt_IOA = iIt_EndIOA = iIt_IOA.toInt(0); iIt_sDscr = iIt_nmBase.length; }
		if(iIt_tp == "ai")			{ iIt_nmBase = iIt_nmBase.length ? iIt_nmBase : "AI"; iIt_vtp = "real,ro"; }
		else if(iIt_tp == "di")	{ iIt_nmBase = iIt_nmBase.length ? iIt_nmBase : "DI"; iIt_vtp = "boolean,ro"; }
		else if(iIt_tp == "do")	{ iIt_nmBase = iIt_nmBase.length ? iIt_nmBase : "DO"; iIt_vtp = "boolean"; }
		else continue;
		while(iIt_IOA <= iIt_EndIOA) {
			aId = iIt_tp+iIt_IOA; aDscr = iIt_nmBase+(iIt_sDscr?"":"["+iIt_IOA+"]"); aWr = (iIt_tp == "do");
			if(items[aId].isEVal()) { items[aId] = itW = new Object(); itW.descr = aDscr; itW.wr = aWr; itW.alarm = 0; }
			if(iIt_flgs.indexOf("a") >= 0) {
				this.attrAdd(aId, aDscr, iIt_vtp);
				if(aWr)	oAVals[aId] = EVAL_INT;
				this[aId].set(EVAL_INT, 0, 0, true);
			}
			iIt_IOA++;
		}
	}
	itemsSet_ = itemsSet;
}

//Check for the transport change and connect
t_err = "";
if(!tr || transport != transport_)	{
	tr = SYS.Transport.nodeAt(transport, ".");
	transport_ = transport;
	if(tr) tr.start(false);
	itemsSet_ = "";
	tmRetr_ = tmRetr;
	STARTDT_act = false;
	items = new Object();
	oAVals = new Object();
}
if(!tr)	t_err = "1:"+tr("Output transport '%1' error.").replace("%1",transport);
else if(!tr.start()) {
	if(tmRetr_ >= tmRetr) {
		tr.start(true);
		bufIn = bufOut = itemsSet_ = "";
		tmRetr_ = t1_ = t1__ = t2_ = t3_ = w_ = 0;
	}
	else tmRetr_ += 1/f_frq;
	if(tr.start()) STARTDT_act = false;
	else t_err = "1:"+tr("Output transport '%1' stoped.").replace("%1",transport);
}
else {
	//Check and finish, U (STOPDT, Act)
	if(f_stop && STARTDT_con) bufOut += SYS.strFromCharCode(0x68, 0x04, 0x10|0x03, 0, 0, 0);

	//Send output buffer and read the transport for an input data
	if(bufOut.length) SYS.messDebug("/IEC60870",tr("Good output sequence")+": "+SYS.strDecode(bufOut,"Bin"," "));
	bufIn += tr.messIO(bufOut, -0.001);
	bufOut = "";
	//Input requests processing
	while(bufIn.length) {
		if(bufIn.length >= 2 && (bufIn.charCodeAt(0) != 0x68 || (seqSz=bufIn.charCodeAt(1)) > 253)) {
			SYS.messDebug("/IEC60870",tr("Wrong sequence, rejected")+": "+SYS.strDecode(bufIn,"Bin"," "));
			bufIn = "";
			break;
		}
		if(bufIn.length < 6 || (bufIn.length-2) < seqSz)	break;		//Not full, wait

		SYS.messDebug("/IEC60870",tr("Good input sequence")+": "+SYS.strDecode(bufIn.slice(0,seqSz+2),"Bin"," "));

		cntRx_ = -1;
		sB1 = bufIn.charCodeAt(2);
		if((sB1&0x3) == 0x3 && (sB1&0x40))			TESTFR_Act = true;	//U (TESTFR, Act)
		else if((sB1&0x3) == 0x3 && (sB1&0x80))	t1__ = 0;				//U (TESTFR, Con)
		else if((sB1&0x3) == 0x3 && (sB1&0x08)) {								//U (STARTDT, Con)
			STARTDT_con = true;
			t1_ = t1__ = t2_ = t3_ = 0;
			cntTx = cntRx = 0;
			destAddr = addr.parse(0,".").toInt();
			destOA = addr.parse(1,".").toInt();
			C_IC_NA_1 = C_SC_NA_1 = 0;
			C_CS_NA_1 = C_CI_NA_1 = false;
		}
		else if(STARTDT_con && (sB1&0x3) == 1)	cntRx_ = (bufIn.charCodeAt(5)>>1)*128 + (bufIn.charCodeAt(4)>>1);		//S (Ack)
		else if(STARTDT_con && (sB1&0x1) == 0) {	//I
			cntTx_ = bufIn.charCodeAt(3)*128 + (sB1>>1);
			if(cntTx_ != cntRx)
				t_err = "2:"+tr("Connection terminated by the input sequence broken, lost input packages, S(R)=%1, S(T)=%2").replace("%1",cntRx.toString()).replace("%2",cntTx_.toString());
			cntRx_ = bufIn.charCodeAt(5)*128 + (bufIn.charCodeAt(4)>>1);
			ASDU_id = bufIn.charCodeAt(6);
			ASDU_els = bufIn.charCodeAt(7);			//7=SQ, 0...6=number
			ASDU_reas = bufIn.charCodeAt(8);			//7=TEST, 6=P/N, 0...5=number
			ASDU_addr = bufIn.charCodeAt(9);
			ASDU_OA = bufIn.charCodeAt(11)*256 + bufIn.charCodeAt(10);
			//destAddr = ASDU_addr, destOA = ASDU_OA;
			isSQ = ASDU_els&0x80;
			ASDU_els = ASDU_els&0x7F;

			cntRx = (cntRx+1)&0x7FFF;
			t2_ = 1/f_frq;	
			w_++;

			if(ASDU_id == 100) {
				if(ASDU_reas == 7)			C_IC_NA_1con = true;	//ActCon
				else if(ASDU_reas == 10)	C_IC_NA_1 = tmPoolAll;//-1;// 1;	//ActTerm, repeate after {tmPoolAll} second
			}
			else if(ASDU_id == 101) {
				if(ASDU_reas == 7)			C_CI_NA_1con = true;	//ActCon
				//else if(ASDU_reas == 10)	C_CI_NA_1 = false;	//ActTerm, repeate after some timeout
			}
			else if(ASDU_id == 103 && ASDU_reas == 7)	C_CS_NA_1con = true;
			else if(ASDU_id == 1) {	//M_SP_NA_1, Single-point information
				if((10+4+(ASDU_els-1)*(isSQ?1:4)) != seqSz)	SYS.messDebug("/IEC60870","M_SP_NA_1: "+tr("Items number is discrepancy to the package size"));
				else for(iEl = 0, iOff = 12; iEl < ASDU_els; iEl++, iOff += 1) {
					if(!isSQ || !iEl)	{ IOA = (bufIn.charCodeAt(iOff+2)<<16) + (bufIn.charCodeAt(iOff+1)<<8) + bufIn.charCodeAt(iOff); iOff += 3; }
					else IOA++;
					inVal("di"+IOA, (SIQ=bufIn.charCodeAt(iOff))&0x01, SIQ);
				}
			}
			else if(ASDU_id == 2) {	//M_SP_TA_1, Single-point information with timestamp
				if((10+4+(ASDU_els-1)*(isSQ?8:11)) != seqSz)	SYS.messDebug("/IEC60870","M_SP_TA_1: "+tr("Items number is discrepancy to the package size"));
				else for(iEl = 0, iOff = 12; iEl < ASDU_els; iEl++, iOff += 8) {
					if(!isSQ || !iEl)	{ IOA = (bufIn.charCodeAt(iOff+2)<<16) + (bufIn.charCodeAt(iOff+1)<<8) + bufIn.charCodeAt(iOff); iOff += 3; }
					else IOA++;
					inVal("di"+IOA, (SIQ=bufIn.charCodeAt(iOff))&0x01, SIQ, false, getTm(bufIn.slice(iOff+1,iOff+8)));
				}
			}
			else if(ASDU_id == 3) {	//M_DP_NA_1, Two-element information
				if((10+4+(ASDU_els-1)*(isSQ?1:4)) != seqSz)	SYS.messDebug("/IEC60870","M_DP_NA_1: "+tr("Items number is discrepancy to the package size"));
				else for(iEl = 0, iOff = 12; iEl < ASDU_els; iEl++, iOff += 1) {
					if(!isSQ || !iEl)	{ IOA = (bufIn.charCodeAt(iOff+2)<<16) + (bufIn.charCodeAt(iOff+1)<<8) + bufIn.charCodeAt(iOff); iOff += 3; }
					else IOA++;
					inVal("di"+IOA, (((SIQ=bufIn.charCodeAt(iOff))&0x3)==0x3||(SIQ&0x3)==0)?EVAL:(SIQ&0x2)?true:false, SIQ);
				}
			}
			else if(ASDU_id == 4) {	//M_DP_TA_1, Two-element information with timestamp
				if((10+4+(ASDU_els-1)*(isSQ?8:11)) != seqSz)	SYS.messDebug("/IEC60870","M_DP_TA_1: "+tr("Items number is discrepancy to the package size"));
				else for(iEl = 0, iOff = 12; iEl < ASDU_els; iEl++, iOff += 8) {
					if(!isSQ || !iEl)	{ IOA = (bufIn.charCodeAt(iOff+2)<<16) + (bufIn.charCodeAt(iOff+1)<<8) + bufIn.charCodeAt(iOff); iOff += 3; }
					else IOA++;
					inVal("di"+IOA, (((SIQ=bufIn.charCodeAt(iOff))&0x3)==0x3||(SIQ&0x3)==0)?EVAL:(SIQ&0x2)?true:false, SIQ, false, getTm(bufIn.slice(iOff+1,iOff+8)));
				}
			}
			else if(ASDU_id == 11) {	//M_ME_NB_1, Measured value, scaled value
				if((10+6+(ASDU_els-1)*(isSQ?3:6)) != seqSz)	SYS.messDebug("/IEC60870","M_ME_NB_1: "+tr("Items number is discrepancy to the package size"));
				else for(iEl = 0, iOff = 12; iEl < ASDU_els; iEl++, iOff += 3) {
					if(!isSQ || !iEl)	{ IOA = (bufIn.charCodeAt(iOff+2)<<16) + (bufIn.charCodeAt(iOff+1)<<8) + bufIn.charCodeAt(iOff); iOff += 3; }
					else IOA++;
					val = (bufIn.charCodeAt(iOff+1)<<8) + bufIn.charCodeAt(iOff);
					if(val > 32767) val -= 65536;
					inVal("ai"+IOA, val, bufIn.charCodeAt(iOff+2));
				}
			}
			else if(ASDU_id == 13) {	//M_ME_NC_1, Measured value, short real value
				if((10+8+(ASDU_els-1)*(isSQ?5:8)) != seqSz)	SYS.messDebug("/IEC60870","M_ME_NC_1: "+tr("Items number is discrepancy to the package size"));
				else for(iEl = 0, iOff = 12; iEl < ASDU_els; iEl++, iOff += 5) {
					if(!isSQ || !iEl)	{ IOA = (bufIn.charCodeAt(iOff+2)<<16) + (bufIn.charCodeAt(iOff+1)<<8) + bufIn.charCodeAt(iOff); iOff += 3; }
					else IOA++;
					inVal("ai"+IOA, Special.FLibSYS.floatMergeWord(bufIn.charCodeAt(iOff+1)*256+bufIn.charCodeAt(iOff),bufIn.charCodeAt(iOff+3)*256+bufIn.charCodeAt(iOff+2)), bufIn.charCodeAt(iOff+4));
				}
			}
			else if(ASDU_id == 36) {	//M_ME_TF_1, Measured value, short real value with timestamp
				if((10+15+(ASDU_els-1)*(isSQ?12:15)) != seqSz)	SYS.messDebug("/IEC60870","M_ME_TF_1: "+tr("Items number is discrepancy to the package size"));
				else for(iEl = 0, iOff = 12; iEl < ASDU_els; iEl++, iOff += 12) {
					if(!isSQ || !iEl)	{ IOA = (bufIn.charCodeAt(iOff+2)<<16) + (bufIn.charCodeAt(iOff+1)<<8) + bufIn.charCodeAt(iOff); iOff += 3; }
					else IOA++;
					inVal("ai"+IOA, Special.FLibSYS.floatMergeWord(bufIn.charCodeAt(iOff+1)*256+bufIn.charCodeAt(iOff),bufIn.charCodeAt(iOff+3)*256+bufIn.charCodeAt(iOff+2)), bufIn.charCodeAt(iOff+4),
						false, getTm(bufIn.slice(iOff+5,iOff+12)));
				}
			}
			else if(ASDU_id == 45) {	//C_SC_NA_1, Single-point confirm
				if((10+4+(ASDU_els-1)*(isSQ?1:4)) != seqSz)	SYS.messDebug("/IEC60870", "C_SC_NA_1: "+tr("Items number is discrepancy to the package size"));
				else for(iEl = 0, iOff = 12; iEl < ASDU_els; iEl++, iOff += 1) {
					if(!isSQ || !iEl)	{ IOA = (bufIn.charCodeAt(iOff+2)<<16) + (bufIn.charCodeAt(iOff+1)<<8) + bufIn.charCodeAt(iOff); iOff += 3; }
					else IOA++;
					inVal("do"+IOA, (SIQ=bufIn.charCodeAt(iOff))&0x01, SIQ);
				}
				C_SC_NA_1 = 0;
			}
			//else ...
		}
		if(cntRx_ >= 0 && cntRx_ == cntTx) t1_ = 0;

		t3_ = 0;
		bufIn = bufIn.slice(seqSz+2);
	}
	//Check and the service negotiation perform.
	while(!t_err.length) {
		if(TESTFR_Act) {
			bufOut += SYS.strFromCharCode(0x68, 0x04, 0x80|0x03, 0, 0, 0);
			TESTFR_Act = false;
		}
		else if(!STARTDT_act)	{	//U (STARTDT, Act);
			bufOut += SYS.strFromCharCode(0x68, 0x04, 0x04|0x03, 0, 0, 0);
			STARTDT_act = true; STARTDT_con = false;
		}
		else if(t1_ > t1)
			t_err = "3:" + tr("Connection terminated by not acknowledge transmited package '%1' by timeout t1 (%2).").replace("%1",cntTx.toString()).replace("%2",t1.toFixed(2));
		else if(t1__ > t1)
			t_err = "4:" + tr("Connection terminated by not confirmed TEST package by timeout t1 (%1).").replace("%1",t1.toFixed(2));
		else if(t3_ > t3) {						//U (TESTFR, Act);
			bufOut += SYS.strFromCharCode(0x68, 0x04, 0x40|0x03, 0, 0, 0);
			t3_ = 0; t1__ = 1/f_frq;
		}
		else if(t2_ > t2 || w_ >= w) {	//S (Ack)
			bufOut += SYS.strFromCharCode(0x68, 0x04, 0x01, 0, (cntRx<<1)&0xFF, cntRx>>7);
			t2_ = w_ = 0;
		}
		else if(STARTDT_con /*&& destAddr >= 0*/) {	//I
			ASDU_ = "";
			// Services process
			if(C_IC_NA_1 > 0)	C_IC_NA_1 = max(0, C_IC_NA_1-1/f_frq);
			else if(C_IC_NA_1 == 0) {
				//Generic acquisition request (20)
				ASDU_ = SYS.strFromCharCode(100, 0x01, 0x06, destAddr, destOA&0xFF, destOA>>8, 0x00, 0x00, 0x00, 0x14);
				C_IC_NA_1 = -1; C_IC_NA_1con = false;
			}
			else if(!C_CI_NA_1) {
				//Generic counters request (5)
				ASDU_ = SYS.strFromCharCode(101, 0x01, 0x06, destAddr, destOA&0xFF, destOA>>8, 0x00, 0x00, 0x00, 0x05);
				C_CI_NA_1 = true; C_CI_NA_1con = false;
			}
			else if(syncTimePLC && !C_CS_NA_1) {
				//Time sync
				tmMs = 0; tm = SYS.time(tmMs); tmMs = (tm%60)*1000+tmMs/1000;
				tmMin = tmHour = tmDay = tmMonth = tmYear = tmWDay = tmIsDst = 0;
				SYS.localtime(tm, 0, tmMin, tmHour, tmDay, tmMonth, tmYear, tmWDay, 0, tmIsDst);
				ASDU_ = SYS.strFromCharCode(103, 0x01, 0x06, destAddr, destOA&0xFF, destOA>>8, 0, 0, 0, tmMs&0xFF, tmMs>>8, tmMin, tmHour|(tmIsDst?0x80:0), tmDay|((tmWDay?tmWDay:7)<<5), tmMonth+1, tmYear-2000);
				C_CS_NA_1 = true; C_CS_NA_1con = false;
			}
			else if((C_SC_NA_1=max(0,C_SC_NA_1-1/f_frq)) == 0) {
				//Check for commands set, C_SC_NA_1 (45)
				cItN = 0; cItSeq = "";
				// By attributes
				for(iIt in oAVals)
					if((aO=this[iIt]) && !(aOval=aO.get()).isEVal() && aOval != oAVals[iIt] && !cItN) {
						IOA = iIt.slice(2).toInt();
						cItSeq += SYS.strFromCharCode(IOA&0xFF, (IOA>>8)&0xFF, IOA>>16, aOval?0x01:0);
						//oAVals[iIt] = aOval;
						cItN++;
					}
				// By items object
				for(iIt in items)
					if((aO=items[iIt]) && !(aOval=aO.set).isEVal() && !cItN) {
						IOA = iIt.slice(2).toInt();
						cItSeq += SYS.strFromCharCode(IOA&0xFF, (IOA>>8)&0xFF, IOA>>16, aOval.toInt()?0x01:0);
						aO.set = EVAL_BOOL;
						cItN++;
					}
				// Finish the request
				if(cItN) {
					ASDU_ = SYS.strFromCharCode(45, cItN, 0x06, destAddr, destOA&0xFF, destOA>>8) + cItSeq;
					C_SC_NA_1 = 1;	//After one second repeat
				}
			}

			// Append header and place to output
			if(ASDU_.length) {
				bufOut += SYS.strFromCharCode(0x68, 4+ASDU_.length, (cntTx<<1)&0xFF, cntTx>>7, (cntRx<<1)&0xFF, cntRx>>7) + ASDU_;
				cntTx = (cntTx+1)&0x7FFF;
				t1_ = 1/f_frq;
				//t2_ = w_ = 0;
			} else break;
		}
		else break;
	}

	if(t1_)	t1_ += 1/f_frq;
	if(t1__)	t1__ += 1/f_frq;
	if(t2_)	t2_ += 1/f_frq;
	t3_ += 1/f_frq;
}

//Error set
if(t_err.length) {
	if(tr && tr.start()) tr.start(false);
	if(f_err != t_err) {
		items = new Object();
		oAVals = new Object();
		aLs = this.nodeList("a_");
		for(iA = 0; iA < aLs.length; iA++)
			if((aPref=aLs[iA].slice(2,4)) == "di" || aPref == "do" || aPref == "ai")
				this[aLs[iA].slice(2)].set(EVAL_INT, 0, 0, true);
		SYS.messDebug("/IEC60870", tr("Error")+": "+t_err);
	}
	f_err = t_err;
}
else f_err = "0";


ID: SSCP
NAME: Shark Slave Communication Protocol
DESCR:
Shark Slave Communication Protocol from EnergoCentrum PLUS, s.r.o.

Author: Roman Savochenko <roman@oscada.org>
Sponsored: Costumer Faster CZ (http://faster.cz)
Version: 0.6.2
License: GPLv2

PROGRAM:
JavaLikeCalc.JavaScript
//Same request to the device
function req(tr, addr, func, data) {
	req = SYS.strFromCharCode(addr, (func>>8)&0xFF, func&0xFF, (data.length>>8)&0xFF, data.length&0xFF) + data;
	//SYS.messInfo("/SSCP",tr("Request")+": "+SYS.strDecode(req,"Bin"," "));
	resp = tr.messIO(req);
	while(resp.length && (resp.length < 5 || (resp.length-5) < ((resp.charCodeAt(3)<<8)|resp.charCodeAt(4))) &&
		(tresp=tr.messIO("")).length) resp += tresp;
	//SYS.messInfo("/SSCP",tr("Response")+": "+SYS.strDecode(resp,"Bin"," "));
	data = resp;
	if(resp.length < 5)
		return tr("3:No a response or the response short.");
	if((resp.length-5) < ((resp.charCodeAt(3)<<8)|resp.charCodeAt(4)))
		return tr("3:Incomplete response.");
	if(resp.charCodeAt(0) != addr)	return tr("4:Invalid host's address received.");
	func_ = ((resp.charCodeAt(1)&0xFF)<<8) | resp.charCodeAt(2);
	if(func_ == 0xfffe)						return tr("4:Unknown function.");
	if(func_ == 0xffff)						return tr("4:Insufficient rights.");
	if((func_&0x3FFF) != func)			return tr("4:Invalid function received.");
	if((func_&0xC000) != 0x8000) {
		opErr = tr("5:Operation error.");
		if(resp.length >= 9) {
			errCod = (resp.charCodeAt(5)<<24) | (resp.charCodeAt(6)<<16) | (resp.charCodeAt(7)<<8) | resp.charCodeAt(8);
			if(errCod == 0x0101)		opErr += " "+tr("Wrong login.");
			else if(errCod == 0x103)	opErr += " "+tr("No such variable.");
			else if(errCod == 0x112)	opErr += " "+tr("Size mismatch.");
			//... Append here for needs
			else opErr += " "+tr("Unknown error %1.").replace("%1",errCod.toString());
		}
		if(resp.length >= 17)	opErr += " "+tr("Destination:")+" "+SYS.strDecode(resp.slice(9),"Bin","")+"h";
		return opErr;
	}
	data = resp.slice(5);
	return "0";
}

//Set transport and init
if(f_start) {
	transport_ = transport;
	tr = SYS.Transport.Sockets.nodeAt("out_"+transport);
	vlist = new Object();
	prcVList = new Array();
	isLogin = false;
	toLoadVarLsts = true;
	aSelList = false;
	list_ = "";
}
if(f_stop) return;

t_err = "0";

//Check for the transport change and connect
if(!tr || transport != transport_)	{
	tr = SYS.Transport.Sockets.nodeAt("out_"+transport);
	transport_ = transport;
}
if(!tr)	t_err = "1:"+tr("Output transport '%1' error.").replace("%1",transport);
else if(addr < 0 || addr > 255)
	t_err = "2:"+tr("Address '%1' out of range [0...255].").replace("%1",addr.toString());
else {
	//Generic information update.
	if(toLoadVarLsts) {
		toLoadVarLsts = false;
		fLs = SYS.system("ls -1 "+listsDir+"/*.vlist");
		for(off = 0; (fln=fLs.parse(0,"\n",off)).length; ) {
			//stTm = SYS.time();
			fl = SYS.fileRead(fln);
			//fl = fl.split("\x0D\x0A");
			//for(iL = 0; iL < fl.length; iL++) {
				//ln = fl[iL];
			for(off1 = 0; (ln=fl.parse(0,"\x0D\x0A",off1)).length; ) {
			//for(off1 = 0; (ln=Special.FLibSYS.strParse(fl,0,"\x0D\x0A",off1)).length; ) {
				off2 = 0;
				vid = ln.parse(0, ";", off2);
				if(vid == "Project" || !(tVl=ln.parse(0,";",off2)).length) continue;
				vid += ":"+tVl;
				//SYS.messInfo("SSCP","vid="+vid);
				vlist[vid] = vO = new Object();
				vO.Type = ln.parse(0, ";", off2);
				vO.CommUid = ln.parse(0, ";", off2).toInt();
				vO.Offset = ln.parse(0, ";", off2).toInt();
				vO.Length = ln.parse(0, ";", off2).toInt();
				vO.ParentTypeFamily = ln.parse(0, ";", off2);
				vO.HistoryId = ln.parse(0, ";", off2);
			}
			//SYS.messInfo("SSCP", "Time="+(SYS.time()-stTm)+"s; length="+fl.length);
		}
		fl = selLst = "";
		//for(tVl in vlist) selLst += tVl+";";
		//this.attrAdd("selList", tr("Appending variable"), "string|sel", selLst+"\n"+selLst);
		//aSelList = this.selList;
		//aSelList.set("");
		for(tVl in vlist) selLst += tVl+"\n";
		this.attrAdd("selList", tr("Allowed variables"), "text|ro");
		aSelList = this.selList;
		aSelList.set(selLst,0,0,true);
	}
	//Check for select a varable and append it to the processing list
	/*if(aSelList && (tVl=aSelList.get()).length) {
		if(list.indexOf(tVl) == -1)
			list += ((list.length && list[list.length-1] != "\n")?"\n":"")+ tVl+"\n";
		aSelList.set("");
	}*/
	//The processing variables list update/form
	if(list != list_) {
		list_ = list;
		prcVList = new Array();
		for(off = 0; (vid=list.parse(0,"\n",off)).length; ) {
			if((vO=vlist[vid]).isEVal()) continue;
			prcVList.push(vO);
			vO.aId = vid.replace(new RegExp("[\\.\\:]+","g"),"_").replace(new RegExp("[\\$\\-]+","g"),"");
			vTp = "string";
			if(vO.Type.indexOf("bool") != -1)			vTp = "boolean";
			else if(vO.Type.indexOf("real") != -1)	vTp = "real";
			else if(vO.Type.indexOf("int") != -1)		vTp = "integer";
			this.attrAdd(vO.aId, vid, vTp+"|ro");
			vO.aO = this[vO.aId];
			//SYS.messInfo("/SSCP","aId="+vO.aId);
		}
	}

	//Same requests
	if(!isLogin) {
		io = SYS.strFromCharCode(0x01, (maxDtFrm>>8)&0xFF, maxDtFrm&0xFF, user.length) +
				user + SYS.strFromCharCode(0x10) + Special.FLibSYS.MD5(pass);
		if(!(t_err=req(tr,addr,0x0100,io)).toInt()) {
			verPrt = io.charCodeAt(0);
			maxDtFrmServ = (io.charCodeAt(1)<<8) | io.charCodeAt(2);
			isLogin = true;
		}
	}
	if(isLogin && !t_err.toInt()) {
		for(iV0 = iV1 = 0; iV0 < prcVList.length; iV0 = iV1) {
			frmSz = frmSzServ = 0;
			io = Special.FLibSYS.IO("", "", "b");
			io.wr(0x80);
			for(iV1 = iV0; iV1 < prcVList.length; iV1++) {
				vO = prcVList[iV1];
				frmSz += vO.Length; frmSzServ += 12;
				if(frmSz >= maxDtFrm || frmSzServ >= maxDtFrmServ) break;
				io.wr(vO.CommUid, "uint32").wr(vO.Offset, "uint32").wr(vO.Length, "uint32");
			}
			//SYS.messInfo("/SSCP","req="+SYS.strDecode(io.string,"Bin"," "));
			t_err = req(tr, addr, 0x0500, io.string); io.pos = 0;
			//SYS.messInfo("/SSCP","resp="+SYS.strDecode(io.string,"Bin"," "));
			for(iV2 = iV0; iV2 < iV1; iV2++) {
				vO = prcVList[iV2];
				//SYS.messInfo("/SSCP","aId="+vO.aId+"; pos="+io.pos);
				if(t_err.toInt()) tVl = EVAL;
				else {
					if(vO.Type.indexOf("bool") != -1 && vO.Length == 1)
						tVl = io.read("int8", 1);
					else if(vO.Type.indexOf("real") != -1 && (vO.Length == 4 || vO.Length == 8))
						tVl = io.read((vO.Length==8)?"double":"float", 1);
					else if(vO.Type.indexOf("int") != -1 && (vO.Length == 2 || vO.Length == 4))
						tVl = io.read((vO.Length==4)?"int32":"int16", 1);
					else if(vO.Type.indexOf("dt") != -1 && vO.Length == 8) {
						tVl = io.read("int64", 1);
						tVl = SYS.strftime(tVl*1e-7-62135596800) + "." + (tVl%10000000).toString(10,7);
					}
					else if(vO.Type.indexOf("time") != -1 && vO.Length == 8) {
						tm = io.read("int64",1)*1e-7;
						lev = 0;
						days = floor(tm/(24*60*60));
						hours = floor(tm/(60*60))%24;
						mins = floor(tm/(60))%60;
						usec = 1e6 * (tm - days*24*60*60 - hours*60*60 - mins*60);
						tVl = "";
						if(days)	{ tVl += days+tr("day"); lev = max(lev,6); }
						if(hours)	{ tVl += (tVl.length?" ":"")+hours+tr("hour"); lev = max(lev,5); }
						if(mins && lev < 6)	{ tVl += (tVl.length?" ":"")+mins+tr("min"); lev = max(lev,4); }
						if((1e-6*usec) > 0.5 && lev < 5)		{ tVl += (tVl.length?" ":"")+(1e-6*usec).toPrecision(3)+tr("s"); lev = max(lev,3); }
						else if((1e-3*usec) > 0.5 && !lev)	{ tVl += (tVl.length?" ":"")+(1e-3*usec).toPrecision(4)+tr("ms"); lev = max(lev,2); }
						else if(usec > 0.5 && !lev)				{ tVl += (tVl.length?" ":"")+usec.toPrecision(4)+tr("us"); lev = max(lev,1); }
						else if(!lev)	tVl += (tVl.length?" ":"")+(1e3*usec).toPrecision(4)+tr("ns");
					}
					else tVl = SYS.strDecode(io.read("char", vO.Length), "Bin", " ");;
				}
				vO.aO.set(tVl, 0, 0, true);
			}
		}
	}
}

f_err = t_err;


ID: m200
NAME: Mercury 200
uk#NAME: Меркурій 200
ru#NAME: Меркурий 200
DESCR:
One phase counter of electricity Mercury 200, 203.2Т, 206 from the firm "Incotex" (http://www.incotexcom.ru)

Author: Arsen Zakojan <godzilla919@gmail.com>
Version: 1.0.0
License: GPLv2

uk#DESCR:
Однофазні лічильники електроенергії Меркурій 200,  203.2Т,  206 компанії Інкотекс (http://www.incotexcom.ru).
Автор: Арсен Закоян <godzilla919@gmail.com>
Версія 1.0.0

ru#DESCR:
Однофазные счетчики электроэнергии Меркурий 200,  203.2Т,  206 компании Инкотекс (http://www.incotexcom.ru).
Автор: Арсен Закоян <godzilla919@gmail.com>
Версия 1.0.0

PROGRAM:
JavaLikeCalc.JavaScript
if(naladchik)//если счетчик закондирован программой Наладчик+
{first=250;
second=3+(8*netaddr);}
else//если обычный сетевой адрес(с завода 6 последних цифр)
{first= floor(netaddr/16777216);//результат деления с округлением в меньшую сторону
second=netaddr-(first*16777216);}//результат вычисления остатка от деления
if(f_start){;t1= EVAL_STR;t2= EVAL_STR;t3= EVAL_STR;t4= EVAL_STR;s= EVAL_STR;U= EVAL_STR;I= EVAL_STR;P= EVAL_STR;}//обнуляем значения
if(tarif)//если выбрано считывание показаний тарифов
{req = SYS.XMLNode("mess").setAttr("ProtIt","m200").setAttr("first",first).setAttr("second",second).setAttr("data",SYS.strFromCharCode(0x27));}
SYS.Transport["Serial"]["out_"+transport].messIO(req,"UserProtocol");
if(req.text().length <23){ answer = EVAL_STR;t1= EVAL_STR;t2= EVAL_STR;t3= EVAL_STR;t4= EVAL_STR;s= EVAL_STR;}//если нет ответа
else //если ответ получен
{t1 =Special.FLibSYS.str2real( req.text().slice(15,17)+req.text().slice(18,20)+req.text().slice(21,23)+req.text().slice(24,26))/100;
t2 =Special.FLibSYS.str2real( req.text().slice(27,29)+req.text().slice(30,32)+req.text().slice(33,35)+req.text().slice(36,38))/100;
t3 =Special.FLibSYS.str2real( req.text().slice(39,41)+req.text().slice(42,44)+req.text().slice(45,47)+req.text().slice(48,50))/100;
t4 =Special.FLibSYS.str2real( req.text().slice(51,53)+req.text().slice(54,56)+req.text().slice(57,59)+req.text().slice(60,62))/100;
s=t1+t2+t3+t4;}
if(UIP)//{//если выбрано считывание мгновенных показаний
{req = SYS.XMLNode().setAttr("ProtIt","m200").setAttr("first",first).setAttr("second",second).setAttr("data",SYS.strFromCharCode(0x63));
SYS.Transport["Serial"]["out_"+transport].messIO(req,"UserProtocol");}
if(req.text().length <14){U= EVAL_STR;I= EVAL_STR;P= EVAL_STR;}//если нет ответа
else//если ответ получен
{U =Special.FLibSYS.str2real( req.text().slice(15,17)+req.text().slice(18,20))/10;
I =Special.FLibSYS.str2real( req.text().slice(21,23)+req.text().slice(24,26))/100;
P =Special.FLibSYS.str2real( req.text().slice(27,29)+req.text().slice(30,32)+req.text().slice(33,35));}


ID: m230
NAME: Mercury 230
uk#NAME: Меркурій 230
ru#NAME: Меркурий 230
DESCR:
Three phase counter of electricity Mercury 230, 231, 232, 233, 234, 236 from the firm "Incotex" (http://www.incotexcom.ru).

Author: Arsen Zakojan <godzilla919@gmail.com>
Version: 1.0.0
License: GPLv2

uk#DESCR:
Трифазні лічильники електроенергії Меркурій 230, 231, 232, 233,  234,  236  компанії Інкотекс (http://www.incotexcom.ru).
Автор: Арсен Закоян <godzilla919@gmail.com>
Версія 1.0

ru#DESCR:
Трехфазные счетчики электроэнергии Меркурий 230, 231, 232, 233,  234,  236  компании Инкотекс (http://www.incotexcom.ru).
Автор: Арсен Закоян <godzilla919@gmail.com>
Версия 1.0

PROGRAM:
JavaLikeCalc.JavaScript
if(f_start)
//очищаем все данные
{answer = EVAL_STR;TSAp  = EVAL_STR;TSAm = EVAL_STR;TSRp = EVAL_STR;TSRm = EVAL_STR;
T1Ap  = EVAL_STR;T1Am = EVAL_STR;T1Rp = EVAL_STR;T1Rm = EVAL_STR;T2Ap  = EVAL_STR;T2Am = EVAL_STR;
T2Rp = EVAL_STR;T2Rm = EVAL_STR; T3Ap  = EVAL_STR;T3Am = EVAL_STR;T3Rp = EVAL_STR;T3Rm = EVAL_STR;
T4Ap  = EVAL_STR;T4Am = EVAL_STR;T4Rp = EVAL_STR;T4Rm = EVAL_STR;
PS = EVAL_STR;P1= EVAL_STR;P2= EVAL_STR;P3= EVAL_STR;U1= EVAL_STR;U2= EVAL_STR;U3= EVAL_STR;
I1= EVAL_STR;I2= EVAL_STR;I3= EVAL_STR;QS= EVAL_STR;Q1= EVAL_STR;Q2= EVAL_STR;Q3= EVAL_STR;
SS= EVAL_STR;S1= EVAL_STR;S2= EVAL_STR;S3= EVAL_STR;KS= EVAL_STR;K1= EVAL_STR;K2= EVAL_STR;
K3= EVAL_STR;F1= EVAL_STR;N1= EVAL_STR;}
//отправка пароля
req = SYS.XMLNode().setAttr("ProtIt","m230").setAttr("netaddr",netaddr).setAttr("data",SYS.strFromCharCode(0x01,0x01,Special.FLibSYS.str2int(password.slice(0,1)),Special.FLibSYS.str2int(password.slice(1,2)),Special.FLibSYS.str2int(password.slice(2,3)),Special.FLibSYS.str2int(password.slice(3,4)),Special.FLibSYS.str2int(password.slice(4,5)),Special.FLibSYS.str2int(password.slice(5,6))));
SYS.Transport["Serial"]["out_"+transport].messIO(req,"UserProtocol");
if(!req.text()) {answer = EVAL_STR;TSAp  = EVAL_STR;TSAm = EVAL_STR;TSRp = EVAL_STR;TSRm = EVAL_STR;
T1Ap  = EVAL_STR;T1Am = EVAL_STR;T1Rp = EVAL_STR;T1Rm = EVAL_STR;T2Ap  = EVAL_STR;T2Am = EVAL_STR;
T2Rp = EVAL_STR;T2Rm = EVAL_STR; T3Ap  = EVAL_STR;T3Am = EVAL_STR;T3Rp = EVAL_STR;T3Rm = EVAL_STR;
T4Ap  = EVAL_STR;T4Am = EVAL_STR;T4Rp = EVAL_STR;T4Rm = EVAL_STR;
PS = EVAL_STR;P1= EVAL_STR;P2= EVAL_STR;P3= EVAL_STR;U1= EVAL_STR;U2= EVAL_STR;U3= EVAL_STR;
I1= EVAL_STR;I2= EVAL_STR;I3= EVAL_STR;QS= EVAL_STR;Q1= EVAL_STR;Q2= EVAL_STR;Q3= EVAL_STR;
SS= EVAL_STR;S1= EVAL_STR;S2= EVAL_STR;S3= EVAL_STR;KS= EVAL_STR;K1= EVAL_STR;K2= EVAL_STR;
K3= EVAL_STR;F1= EVAL_STR;N1= EVAL_STR;return;}
else answer =req.text();
//Энергия от сброса сумма Т
if(TS){
req = SYS.XMLNode().setAttr("ProtIt","m230").setAttr("netaddr",netaddr).setAttr("data",SYS.strFromCharCode(0x05,0x00,0x00));
SYS.Transport["Serial"]["out_"+transport].messIO(req,"UserProtocol");
if(!req.text()){TSAp  = EVAL_STR;TSAm = EVAL_STR;TSRp = EVAL_STR;TSRm = EVAL_STR; }
else {
if(req.text().slice(0,10)!=2147483647)TSAp=req.text().slice(0,10)/1000;
else TSAp= EVAL_STR;
if(req.text().slice(10,20)!=2147483647)TSAm=req.text().slice(10,20)/1000;
else TSAm= EVAL_STR;
if(req.text().slice(20,30)!=2147483647)TSRp=req.text().slice(20,30)/1000;
else TSRp= EVAL_STR;
if(req.text().slice(30,40)!=2147483647)TSAm=req.text().slice(30,40)/1000;
else TSRm= EVAL_STR;}
}
if(T1){
//Энергия от сброса Т1
req = SYS.XMLNode().setAttr("ProtIt","m230").setAttr("netaddr",netaddr).setAttr("data",SYS.strFromCharCode(0x05,0x00,0x01));
SYS.Transport["Serial"]["out_"+transport].messIO(req,"UserProtocol");
if(!req.text()){T1Ap  = EVAL_STR;T1Am = EVAL_STR;T1Rp = EVAL_STR;T1Rm = EVAL_STR; }
else {
if(req.text().slice(0,10)!=2147483647)T1Ap=req.text().slice(0,10)/1000;
else T1Ap= EVAL_STR;
if(req.text().slice(10,20)!=2147483647)T1Am=req.text().slice(10,20)/1000;
else T1Am= EVAL_STR;
if(req.text().slice(20,30)!=2147483647)T1Rp=req.text().slice(20,30)/1000;
else T1Rp= EVAL_STR;
if(req.text().slice(30,40)!=2147483647)T1Am=req.text().slice(30,40)/1000;
else T1Rm= EVAL_STR;}
}
//Энергия от сброса Т2
if(T2){
req = SYS.XMLNode().setAttr("ProtIt","m230").setAttr("netaddr",netaddr).setAttr("data",SYS.strFromCharCode(0x05,0x00,0x02));
SYS.Transport["Serial"]["out_"+transport].messIO(req,"UserProtocol");
if(!req.text()){T2Ap  = EVAL_STR;T2Am = EVAL_STR;T2Rp = EVAL_STR;T2Rm = EVAL_STR; }
else {
if(req.text().slice(0,10)!=2147483647)T2Ap=req.text().slice(0,10)/1000;
else T2Ap= EVAL_STR;
if(req.text().slice(10,20)!=2147483647)T2Am=req.text().slice(10,20)/1000;
else T2Am= EVAL_STR;
if(req.text().slice(20,30)!=2147483647)T2Rp=req.text().slice(20,30)/1000;
else T2Rp= EVAL_STR;
if(req.text().slice(30,40)!=2147483647)T2Am=req.text().slice(30,40)/1000;
else T2Rm= EVAL_STR;}
}
//Энергия от сброса Т3
if(T3){
req = SYS.XMLNode().setAttr("ProtIt","m230").setAttr("netaddr",netaddr).setAttr("data",SYS.strFromCharCode(0x05,0x00,0x03));
SYS.Transport["Serial"]["out_"+transport].messIO(req,"UserProtocol");
if(!req.text()){T3Ap  = EVAL_STR;T3Am = EVAL_STR;T3Rp = EVAL_STR;T3Rm = EVAL_STR; }
else {
if(req.text().slice(0,10)!=2147483647)T3Ap=req.text().slice(0,10)/1000;
else T3Ap= EVAL_STR;
if(req.text().slice(10,20)!=2147483647)T3Am=req.text().slice(10,20)/1000;
else T3Am= EVAL_STR;
if(req.text().slice(20,30)!=2147483647)T3Rp=req.text().slice(20,30)/1000;
else T3Rp= EVAL_STR;
if(req.text().slice(30,40)!=2147483647)T3Am=req.text().slice(30,40)/1000;
else T3Rm= EVAL_STR;}
}
//Энергия от сброса Т4
if(T4){
req = SYS.XMLNode().setAttr("ProtIt","m230").setAttr("netaddr",netaddr).setAttr("data",SYS.strFromCharCode(0x05,0x00,0x04));
SYS.Transport["Serial"]["out_"+transport].messIO(req,"UserProtocol");
if(!req.text()){T4Ap  = EVAL_STR;T4Am = EVAL_STR;T4Rp = EVAL_STR;T4Rm = EVAL_STR; }
else {
if(req.text().slice(0,10)!=2147483647)T4Ap=req.text().slice(0,10)/1000;
else T4Ap= EVAL_STR;
if(req.text().slice(10,20)!=2147483647)T4Am=req.text().slice(10,20)/1000;
else T4Am= EVAL_STR;
if(req.text().slice(20,30)!=2147483647)T4Rp=req.text().slice(20,30)/1000;
else T4Rp= EVAL_STR;
if(req.text().slice(30,40)!=2147483647)T4Am=req.text().slice(30,40)/1000;
else T4Rm= EVAL_STR;}
}
//Мощность P
if(P){
req = SYS.XMLNode().setAttr("ProtIt","m230").setAttr("netaddr",netaddr).setAttr("data",SYS.strFromCharCode(0x08,0x16,0x00));
SYS.Transport["Serial"]["out_"+transport].messIO(req,"UserProtocol");
if(!req.text()){PS=EVAL_STR;P1=EVAL_STR;P2=EVAL_STR;P3=EVAL_STR;}
else PS=req.text().slice(0,7)/100;P1=req.text().slice(7,14)/100;P2=req.text().slice(14,21)/100;P3=req.text().slice(21,28)/100;}
//Мощность Q
if(Q){
req = SYS.XMLNode().setAttr("ProtIt","m230").setAttr("netaddr",netaddr).setAttr("data",SYS.strFromCharCode(0x08,0x16,0x04));
SYS.Transport["Serial"]["out_"+transport].messIO(req,"UserProtocol");
if(!req.text()){QS=EVAL_REAL;Q1=EVAL_REAL;Q2=EVAL_REAL;Q3=EVAL_REAL;}
else 
{if (req.text().slice(28,29)==4||req.text().slice(28,29)=="C")QS=(req.text().slice(0,7)/100)*-1;
else QS=(req.text().slice(0,7)/100);
if (req.text().slice(29,30)==4||req.text().slice(29,30)=="C")Q1=(req.text().slice(7,14)/100)*-1;
else Q1=(req.text().slice(7,14)/100);
if (req.text().slice(30,31)==4||req.text().slice(30,31)=="C")Q2=(req.text().slice(14,21)/100)*-1;
else Q2=(req.text().slice(14,21)/100);
if (req.text().slice(31,32)==4||req.text().slice(31,32)=="C")Q3=(req.text().slice(21,28)/100)*-1;
else Q3=(req.text().slice(21,28)/100);}}
//Мощность S
if(S){
req = SYS.XMLNode().setAttr("ProtIt","m230").setAttr("netaddr",netaddr).setAttr("data",SYS.strFromCharCode(0x08,0x16,0x08));
SYS.Transport["Serial"]["out_"+transport].messIO(req,"UserProtocol");
if(!req.text()){SS=EVAL_STR;S1=EVAL_STR;S2=EVAL_STR;S3=EVAL_STR;}
else SS=req.text().slice(0,7)/100;S1=req.text().slice(7,14)/100;S2=req.text().slice(14,21)/100;S3=req.text().slice(21,28)/100;}
// Напряжение U
if(U){
req = SYS.XMLNode().setAttr("ProtIt","m230").setAttr("netaddr",netaddr).setAttr("data",SYS.strFromCharCode(0x08,0x16,0x11));
SYS.Transport["Serial"]["out_"+transport].messIO(req,"UserProtocol");
if(!req.text()){U1=EVAL_STR;U2=EVAL_STR;U3=EVAL_STR;}
else U1=req.text().slice(0,8)/100;U2=req.text().slice(8,16)/100;U3=req.text().slice(16,24)/100;}
//Ток I
if(I){
req = SYS.XMLNode().setAttr("ProtIt","m230").setAttr("netaddr",netaddr).setAttr("data",SYS.strFromCharCode(0x08,0x16,0x21));
SYS.Transport["Serial"]["out_"+transport].messIO(req,"UserProtocol");
if(!req.text()){I1=EVAL_STR;I2=EVAL_STR;I3=EVAL_STR;}
else I1=req.text().slice(0,8)/1000;I2=req.text().slice(8,16)/1000;I3=req.text().slice(16,24)/1000;}
//Коэффициент мощности
if(K){
req = SYS.XMLNode().setAttr("ProtIt","m230").setAttr("netaddr",netaddr).setAttr("data",SYS.strFromCharCode(0x08,0x16,0x30));
SYS.Transport["Serial"]["out_"+transport].messIO(req,"UserProtocol");
if(!req.text()){KS=EVAL_STR;K1=EVAL_STR;K2=EVAL_STR;K3=EVAL_STR;}
else KS=req.text().slice(0,7)/1000;K1=req.text().slice(7,14)/1000;K2=req.text().slice(14,21)/1000;K3=req.text().slice(21,28)/1000;}
//частота F
if(F){
req = SYS.XMLNode().setAttr("ProtIt","m230").setAttr("netaddr",netaddr).setAttr("data",SYS.strFromCharCode(0x08,0x16,0x40));
SYS.Transport["Serial"]["out_"+transport].messIO(req,"UserProtocol");
if(!req.text())F1= EVAL_STR;
else F1 =req.text();}
//серийный номер
if(N){
req = SYS.XMLNode().setAttr("ProtIt","m230").setAttr("netaddr",netaddr).setAttr("data",SYS.strFromCharCode(0x08,0x00));
SYS.Transport["Serial"]["out_"+transport].messIO(req,"UserProtocol");
if(!req.text())N1= EVAL_STR;
else N1 =req.text();}


ID: Nik2303I
NAME: Nik2303I
DESCR:
Three phase counter of electricity NIK 2303 from firm NIK LLC (http://www.nik.net.ua).

Author: Ruslan Yarmoliuk <rylio74@gmail.com>
Version: 1.0.0
License: GPLv2

PROGRAM:
JavaLikeCalc.JavaScript
using Special.FLibSYS;

if(f_start) {
	transport_ = transport;
	tr = SYS.Transport.nodeAt(transport,".");
	LLC = SYS.strFromCharCode(0xe6, 0xe6, 0x00);
	F_id = SYS.strFromCharCode(0xC0, 0x01, 0x81, 0x00, 0x03);
	end = SYS.strFromCharCode(0x02, 0x00);
	Ae=Ae_=Re=Re_=Ae1=Ae_1=Re1=Re_1=Ae2=Ae_2=Re2=Re_2=Ae3=Ae_3=Re3=Re_3=EVAL_REAL;
	U1=U2=U3=I1=I2=I3=Psum=P1=P2=P3=Qsum=Q1=Q2=Q3=kP1=kP2=kP3=EVAL_REAL;
	V12=V13=EVAL_INT;

}
if(f_stop) {
	return;
}
 
tErr="0";
//Check for the transport change and connect
if(!tr || transport != transport_)	{
	tr = SYS.Transport.nodeAt(transport,".");
	transport_ = transport;
}
tr.start(true, 0);
/* timeout=SYS.time();
	while(!tr.start()){
		if(SYS.time()>timeout+5)break;
	}	
*/	
if(!tr.start()){ tErr = "1:"+tr("Output transport '%1' error.").replace("%1",transport);
			Ae=Ae_=Re=Re_=Ae1=Ae_1=Re1=Re_1=U1=U2=U3=I1=I2=I3=Psum=P1=P2=P3=Qsum=Q1=Q2=Q3=kP1=kP2=kP3=EVAL_REAL;
			V12=V13=EVAL_INT;
}else{
	req = SYS.XMLNode("mess").setAttr("ProtIt","NIK2303").setAttr("SN",serial.toInt(10));
	//COMAND_SNRM
	req.setAttr("cntr",0x93).setText("");
	tr.messIO(req, "UserProtocol");
	if (req.attr("err").toInt()){SYS.messDebug("/NIK2303I/TMPL",tr("Error response")+": "+req.attr("err"));
		Ae=Ae_=Re=Re_=Ae1=Ae_1=Re1=Re_1=U1=U2=U3=I1=I2=I3=Psum=P1=P2=P3=Qsum=Q1=Q2=Q3=kP1=kP2=kP3=EVAL_REAL;
		V12=V13=EVAL_INT;
		return;}
	//COMAND_AARQ (передача пароля)	
	mess = SYS.strFromCharCode(0xa1, 0x09, 0x06, 0x07, 0x60,
		0x85, 0x74, 0x05, 0x08, 0x01, 0x01, 0x8a, 0x02,
		0x07, 0x80, 0x8b, 0x07, 0x60, 0x85, 0x74, 0x05,
		0x08, 0x02, 0x01, 0xac, 0x12, 0x80, 0x11, 0x00)
		+ passw + SYS.strFromCharCode(0xbe, 0x10, 0x04,	
		0x0e, 0x01, 0x00, 0x00, 0x00, 0x06, 0x5f, 0x1f,
		0x04, 0x00, 0x00, 0x08, 0xcb, 0x00, 0x80 );
	req.setAttr("cntr",0x10).setText(LLC + SYS.strFromCharCode(0x60, mess.length) + mess);
	tr.messIO(req, "UserProtocol");
	if (req.attr("err").toInt()){SYS.messDebug("/NIK2303I/TMPL",tr("Error response")+": "+req.attr("err"));
		Ae=Ae_=Re=Re_=Ae1=Ae_1=Re1=Re_1=Ua=Ub=Uc=Ia=Ib=Ic=Pa=Pb=Pc=Qa=Qb=Qc=kPa=kPb=kPc=EVAL_REAL;
		Vab=Vac=EVAL_INT;
		return;}
//ЗАПИТИ ПОТОЧНИХ ПОКАЗНИКІВ ЛІЧИЛЬНИКА T0
	if (T0)	{
		//Запит показник Активна енергія	(1.8.0)
		req.setAttr("cntr",0x10).setText(LLC+F_id+SYS.strFromCharCode( 1, 0, 1, 8, 0, 255)+end);
		tr.messIO(req, "UserProtocol");
		if (req.attr("err").toInt()){Ae = EVAL_REAL; tErr = "2:"+req.attr("err");}
		else	Ae = kT*((req.text().charCodeAt(9)<<40)+(req.text().charCodeAt(10)<<32)+(req.text().charCodeAt(11)<<24)+(req.text().charCodeAt(12)<<16)+(req.text().charCodeAt(13)<<8)+req.text().charCodeAt(14).toInt())/100000;
	//Запит показник Активна енергія генерація	(2.8.0)
		req.setAttr("cntr",0x10).setText(LLC+F_id+SYS.strFromCharCode( 1, 0, 2, 8, 0, 255)+end);
		tr.messIO(req, "UserProtocol");
		if (req.attr("err").toInt()){Ae_ = EVAL_REAL; tErr = "2:"+req.attr("err");}
		else	Ae_ = kT*((req.text().charCodeAt(9)<<40)+(req.text().charCodeAt(10)<<32)+(req.text().charCodeAt(11)<<24)+(req.text().charCodeAt(12)<<16)+(req.text().charCodeAt(13)<<8)+req.text().charCodeAt(14).toInt())/100000;
	//Запит показник реактивна енергія	 (3.8.0)
		req.setAttr("cntr",0x10).setText(LLC+F_id+SYS.strFromCharCode( 1, 0, 3, 8, 0, 255)+end);
		tr.messIO(req, "UserProtocol");
		if (req.attr("err").toInt()){Re = EVAL_REAL; tErr = "2:"+req.attr("err");}
		else	Re = kT*((req.text().charCodeAt(9)<<40)+(req.text().charCodeAt(10)<<32)+(req.text().charCodeAt(11)<<24)+(req.text().charCodeAt(12)<<16)+(req.text().charCodeAt(13)<<8)+req.text().charCodeAt(14).toInt())/100000;
	//Запит показник реактивна енергія генерація (4.8.0)	
		req.setAttr("cntr",0x10).setText(LLC+F_id+SYS.strFromCharCode( 1, 0, 4, 8, 0, 255)+end);
		tr.messIO(req, "UserProtocol");
		if (req.attr("err").toInt()){Re_ = EVAL_REAL; tErr = "2:"+req.attr("err");}
		else	Re_ = kT*((req.text().charCodeAt(9)<<40)+(req.text().charCodeAt(10)<<32)+(req.text().charCodeAt(11)<<24)+(req.text().charCodeAt(12)<<16)+(req.text().charCodeAt(13)<<8)+req.text().charCodeAt(14).toInt())/100000;
	}
	//ЗАПИТИ ПОТОЧНИХ ПОКАЗНИКІВ ЛІЧИЛЬНИКА T1
	if (T1)	{
		//Запит показник Активна енергія	(1.8.1)
		req.setAttr("cntr",0x10).setText(LLC+F_id+SYS.strFromCharCode( 1, 0, 1, 8, 1, 255)+end);
		tr.messIO(req, "UserProtocol");
		if (req.attr("err").toInt()){Ae1 = EVAL_REAL; tErr = "2:"+req.attr("err");}
		else	Ae1 = kT*((req.text().charCodeAt(9)<<40)+(req.text().charCodeAt(10)<<32)+(req.text().charCodeAt(11)<<24)+(req.text().charCodeAt(12)<<16)+(req.text().charCodeAt(13)<<8)+req.text().charCodeAt(14).toInt())/100000;
	//Запит показник Активна енергія генерація	(2.8.1)
		req.setAttr("cntr",0x10).setText(LLC+F_id+SYS.strFromCharCode( 1, 0, 2, 8, 1, 255)+end);
		tr.messIO(req, "UserProtocol");
		if (req.attr("err").toInt()){Ae_1 = EVAL_REAL; tErr = "2:"+req.attr("err");}
		else	Ae_1 = kT*((req.text().charCodeAt(9)<<40)+(req.text().charCodeAt(10)<<32)+(req.text().charCodeAt(11)<<24)+(req.text().charCodeAt(12)<<16)+(req.text().charCodeAt(13)<<8)+req.text().charCodeAt(14).toInt())/100000;
	//Запит показник реактивна енергія	 (3.8.1)
		req.setAttr("cntr",0x10).setText(LLC+F_id+SYS.strFromCharCode( 1, 0, 3, 8, 1, 255)+end);
		tr.messIO(req, "UserProtocol");
		if (req.attr("err").toInt()){Re1 = EVAL_REAL; tErr = "2:"+req.attr("err");}
		else	Re1 = kT*((req.text().charCodeAt(9)<<40)+(req.text().charCodeAt(10)<<32)+(req.text().charCodeAt(11)<<24)+(req.text().charCodeAt(12)<<16)+(req.text().charCodeAt(13)<<8)+req.text().charCodeAt(14).toInt())/100000;
	//Запит показник реактивна енергія генерація (4.8.1)	
		req.setAttr("cntr",0x10).setText(LLC+F_id+SYS.strFromCharCode( 1, 0, 4, 8, 1, 255)+end);
		tr.messIO(req, "UserProtocol");
		if (req.attr("err").toInt()){Re_1 = EVAL_REAL; tErr = "2:"+req.attr("err");}
		else	Re_1 = kT*((req.text().charCodeAt(9)<<40)+(req.text().charCodeAt(10)<<32)+(req.text().charCodeAt(11)<<24)+(req.text().charCodeAt(12)<<16)+(req.text().charCodeAt(13)<<8)+req.text().charCodeAt(14).toInt())/100000;
	}
	//ЗАПИТИ ПОТОЧНИХ ПОКАЗНИКІВ ЛІЧИЛЬНИКА T2
	if (T2)	{
		//Запит показник Активна енергія	(1.8.2)
		req.setAttr("cntr",0x10).setText(LLC+F_id+SYS.strFromCharCode( 1, 0, 1, 8, 2, 255)+end);
		tr.messIO(req, "UserProtocol");
		if (req.attr("err").toInt()){Ae2 = EVAL_REAL; tErr = "2:"+req.attr("err");}
		else	Ae2 = kT*((req.text().charCodeAt(9)<<40)+(req.text().charCodeAt(10)<<32)+(req.text().charCodeAt(11)<<24)+(req.text().charCodeAt(12)<<16)+(req.text().charCodeAt(13)<<8)+req.text().charCodeAt(14).toInt())/100000;
	//Запит показник Активна енергія генерація	(2.8.2)
		req.setAttr("cntr",0x10).setText(LLC+F_id+SYS.strFromCharCode( 1, 0, 2, 8, 2, 255)+end);
		tr.messIO(req, "UserProtocol");
		if (req.attr("err").toInt()){Ae_2 = EVAL_REAL; tErr = "2:"+req.attr("err");}
		else	Ae_2 = kT*((req.text().charCodeAt(9)<<40)+(req.text().charCodeAt(10)<<32)+(req.text().charCodeAt(11)<<24)+(req.text().charCodeAt(12)<<16)+(req.text().charCodeAt(13)<<8)+req.text().charCodeAt(14).toInt())/100000;
	//Запит показник реактивна енергія	 (3.8.2)
		req.setAttr("cntr",0x10).setText(LLC+F_id+SYS.strFromCharCode( 1, 0, 3, 8, 2, 255)+end);
		tr.messIO(req, "UserProtocol");
		if (req.attr("err").toInt()){Re2 = EVAL_REAL; tErr = "2:"+req.attr("err");}
		else	Re2 = kT*((req.text().charCodeAt(9)<<40)+(req.text().charCodeAt(10)<<32)+(req.text().charCodeAt(11)<<24)+(req.text().charCodeAt(12)<<16)+(req.text().charCodeAt(13)<<8)+req.text().charCodeAt(14).toInt())/100000;
	//Запит показник реактивна енергія генерація (4.8.2)	
		req.setAttr("cntr",0x10).setText(LLC+F_id+SYS.strFromCharCode( 1, 0, 4, 8, 2, 255)+end);
		tr.messIO(req, "UserProtocol");
		if (req.attr("err").toInt()){Re_2 = EVAL_REAL; tErr = "2:"+req.attr("err");}
		else	Re_2 = kT*((req.text().charCodeAt(9)<<40)+(req.text().charCodeAt(10)<<32)+(req.text().charCodeAt(11)<<24)+(req.text().charCodeAt(12)<<16)+(req.text().charCodeAt(13)<<8)+req.text().charCodeAt(14).toInt())/100000;
	}
	//ЗАПИТИ ПОТОЧНИХ ПОКАЗНИКІВ ЛІЧИЛЬНИКА T3
	if (T3)	{
		//Запит показник Активна енергія	(1.8.3)
		req.setAttr("cntr",0x10).setText(LLC+F_id+SYS.strFromCharCode( 1, 0, 1, 8, 3, 255)+end);
		tr.messIO(req, "UserProtocol");
		if (req.attr("err").toInt()){Ae3 = EVAL_REAL; tErr = "2:"+req.attr("err");}
		else	Ae3 = kT*((req.text().charCodeAt(9)<<40)+(req.text().charCodeAt(10)<<32)+(req.text().charCodeAt(11)<<24)+(req.text().charCodeAt(12)<<16)+(req.text().charCodeAt(13)<<8)+req.text().charCodeAt(14).toInt())/100000;
	//Запит показник Активна енергія генерація	(2.8.3)
		req.setAttr("cntr",0x10).setText(LLC+F_id+SYS.strFromCharCode( 1, 0, 2, 8, 3, 255)+end);
		tr.messIO(req, "UserProtocol");
		if (req.attr("err").toInt()){Ae_3 = EVAL_REAL; tErr = "2:"+req.attr("err");}
		else	Ae_3 = kT*((req.text().charCodeAt(9)<<40)+(req.text().charCodeAt(10)<<32)+(req.text().charCodeAt(11)<<24)+(req.text().charCodeAt(12)<<16)+(req.text().charCodeAt(13)<<8)+req.text().charCodeAt(14).toInt())/100000;
	//Запит показник реактивна енергія	 (3.8.3)
		req.setAttr("cntr",0x10).setText(LLC+F_id+SYS.strFromCharCode( 1, 0, 3, 8, 3, 255)+end);
		tr.messIO(req, "UserProtocol");
		if (req.attr("err").toInt()){Re3 = EVAL_REAL; tErr = "2:"+req.attr("err");}
		else	Re3 = kT*((req.text().charCodeAt(9)<<40)+(req.text().charCodeAt(10)<<32)+(req.text().charCodeAt(11)<<24)+(req.text().charCodeAt(12)<<16)+(req.text().charCodeAt(13)<<8)+req.text().charCodeAt(14).toInt())/100000;
	//Запит показник реактивна енергія генерація (4.8.3)	
		req.setAttr("cntr",0x10).setText(LLC+F_id+SYS.strFromCharCode( 1, 0, 4, 8, 3, 255)+end);
		tr.messIO(req, "UserProtocol");
		if (req.attr("err").toInt()){Re_3 = EVAL_REAL; tErr = "2:"+req.attr("err");}
		else	Re_3 = kT*((req.text().charCodeAt(9)<<40)+(req.text().charCodeAt(10)<<32)+(req.text().charCodeAt(11)<<24)+(req.text().charCodeAt(12)<<16)+(req.text().charCodeAt(13)<<8)+req.text().charCodeAt(14).toInt())/100000;
	}
//ЗАПИТИ МИТТЄВИХ ЗНАЧЕНЬ	
	if (U )	{ 		//Напруга
	//Запит напруга фаза 1	
		req.setAttr("cntr",0x10).setText(LLC+F_id+SYS.strFromCharCode( 1, 0, 32, 7, 0, 255)+end);
		tr.messIO(req, "UserProtocol");
		if (req.attr("err").toInt()){U1 = EVAL_REAL; tErr = "2:"+req.attr("err");}
		else	U1 = (req.text().slice(9, 17).replace(",",".").toReal());
	//Запит напруга фаза  2	
		req.setAttr("cntr",0x10).setText(LLC+F_id+SYS.strFromCharCode( 1, 0, 52, 7, 0, 255)+end);
		tr.messIO(req, "UserProtocol");
		if (req.attr("err").toInt()){U2 = EVAL_REAL; tErr = "2:"+req.attr("err");}
		else	U2 = (req.text().slice(9, 17).replace(",",".").toReal());
	//Запит напруга фаза  3	
		req.setAttr("cntr",0x10).setText(LLC+F_id+SYS.strFromCharCode( 1, 0, 72, 7, 0, 255)+end);
		tr.messIO(req, "UserProtocol");
		if (req.attr("err").toInt()){U3 = EVAL_REAL; tErr = "2:"+req.attr("err");}
		else	U3 = (req.text().slice(9, 17).replace(",",".").toReal());
	}
	if(I){ 		//СТРУМ	
	//Запит струм фаза 1	
		req.setAttr("cntr",0x10).setText(LLC+F_id+SYS.strFromCharCode( 1, 0, 31, 7, 0, 255)+end);
		tr.messIO(req, "UserProtocol");
		if (req.attr("err").toInt()){I1 = EVAL_REAL; tErr = "2:"+req.attr("err");}
		else	I1 = kT*(req.text().slice(9, 17).replace(",",".").toReal());
	//Запит струм фаза 2	
		req.setAttr("cntr",0x10).setText(LLC+F_id+SYS.strFromCharCode( 1, 0, 51, 7, 0, 255)+end);
		tr.messIO(req, "UserProtocol");
		if (req.attr("err").toInt()){I2 = EVAL_REAL; tErr = "2:"+req.attr("err");}
		else	I2 = kT*(req.text().slice(9, 17).replace(",",".").toReal());
	//Запит струм фаза 3	
		req.setAttr("cntr",0x10).setText(LLC+F_id+SYS.strFromCharCode( 1, 0, 71, 7, 0, 255)+end);
		tr.messIO(req, "UserProtocol");
		if (req.attr("err").toInt()){I3 = EVAL_REAL; tErr = "2:"+req.attr("err");}
		else	I3 = kT*(req.text().slice(9, 17).replace(",",".").toReal());
		}
	if(P){		//Потужність
	//Запит потужність сумарна
		req.setAttr("cntr",0x10).setText(LLC+F_id+SYS.strFromCharCode( 1, 0, 1, 7, 0, 254)+end);
		tr.messIO(req, "UserProtocol");
		if (req.attr("err").toInt()){Psum = EVAL_REAL; tErr = "2:"+req.attr("err");}
		else	Psum = kT*(req.text().slice(9, 17).replace(",",".").toReal());
	//Запит потужність фаза 1
		req.setAttr("cntr",0x10).setText(LLC+F_id+SYS.strFromCharCode( 1, 128, 21, 7, 0, 0)+end);
		tr.messIO(req, "UserProtocol");
		if (req.attr("err").toInt()){P1 = EVAL_REAL; tErr = "2:"+req.attr("err");}
		else	P1 = kT*(req.text().slice(9, 17).replace(",",".").toReal());
	//Запит потужність фаза 2	
		req.setAttr("cntr",0x10).setText(LLC+F_id+SYS.strFromCharCode( 1, 128, 41, 7, 0, 0)+end);
		tr.messIO(req, "UserProtocol");
		if (req.attr("err").toInt()){P2 = EVAL_REAL; tErr = "2:"+req.attr("err");}
		else	P2 = kT*(req.text().slice(9, 17).replace(",",".").toReal());
	//Запит потужність фаза 3	
		req.setAttr("cntr",0x10).setText(LLC+F_id+SYS.strFromCharCode( 1, 128, 61, 7, 0, 0)+end);
		tr.messIO(req, "UserProtocol");
		if (req.attr("err").toInt()){P3 = EVAL_REAL; tErr = "2:"+req.attr("err");}
		else	P3 = kT*(req.text().slice(9, 17).replace(",",".").toReal());
	}
	if(kP){		//Коефіцієнт потужності
	//Запит коефіцієнт потужності фаза 1	
		req.setAttr("cntr",0x10).setText(LLC+F_id+SYS.strFromCharCode( 1, 0, 33, 7, 0, 255)+end);
		tr.messIO(req, "UserProtocol");
		if (req.attr("err").toInt()){kP1 = EVAL_REAL; tErr = "2:"+req.attr("err");}
		else	kP1 = (req.text().slice(9, 17).replace(",",".").toReal());		
	//Запит коефіцієнт потужності фаза 2	
		req.setAttr("cntr",0x10).setText(LLC+F_id+SYS.strFromCharCode( 1, 0, 53, 7, 0, 255)+end);
		tr.messIO(req, "UserProtocol");
		if (req.attr("err").toInt()){kP2 = EVAL_REAL; tErr = "2:"+req.attr("err");}
		else	kP2 = (req.text().slice(9, 17).replace(",",".").toReal());		
	//Запит коефіцієнт потужності фаза 3	
		req.setAttr("cntr",0x10).setText(LLC+F_id+SYS.strFromCharCode( 1, 0, 73, 7, 0, 255)+end);
		tr.messIO(req, "UserProtocol");
		if (req.attr("err").toInt()){kP3 = EVAL_REAL; tErr = "2:"+req.attr("err");}
		else	kP3 = (req.text().slice(9, 17).replace(",",".").toReal());
	}
	if(Q){	//Реактивна потужність
	//Запит реактивна потужність сумарна	
		req.setAttr("cntr",0x10).setText(LLC+F_id+SYS.strFromCharCode( 1, 0, 3, 7, 0, 254)+end);
		tr.messIO(req, "UserProtocol");
		if (req.attr("err").toInt()){Qsum = EVAL_REAL; tErr = "2:"+req.attr("err");}
		else	Qsum = kT*(req.text().slice(9, 17).replace(",",".").toReal());
	//Запит реактивна потужність фаза 1	
		req.setAttr("cntr",0x10).setText(LLC+F_id+SYS.strFromCharCode( 1, 128, 23, 7, 0, 0)+end);
		tr.messIO(req, "UserProtocol");
		if (req.attr("err").toInt()){Q1 = EVAL_REAL; tErr = "2:"+req.attr("err");}
		else	Q1 = kT*(req.text().slice(9, 17).replace(",",".").toReal());
	//Запит реактивна потужність фаза B	
		req.setAttr("cntr",0x10).setText(LLC+F_id+SYS.strFromCharCode( 1, 128, 43, 7, 0, 0)+end);
		tr.messIO(req, "UserProtocol");
		if (req.attr("err").toInt()){Q2 = EVAL_REAL; tErr = "2:"+req.attr("err");}
		else	Q2 = kT*(req.text().slice(9, 17).replace(",",".").toReal());
	//Запит реактивна потужність фаза 3	
		req.setAttr("cntr",0x10).setText(LLC+F_id+SYS.strFromCharCode( 1, 128, 63, 7, 0, 0)+end);
		tr.messIO(req, "UserProtocol");
		if (req.attr("err").toInt()){Q3 = EVAL_REAL; tErr = "2:"+req.attr("err");}
		else	Q3 = kT*(req.text().slice(9, 17).replace(",",".").toReal());
	}
	if(K){
	//Запит кута між векторами U1_U2	
		req.setAttr("cntr",0x10).setText(LLC+F_id+SYS.strFromCharCode( 1, 128, 33, 7, 0, 0)+end);
		tr.messIO(req, "UserProtocol");
		if (req.attr("err").toInt()){V12 = EVAL_INT; tErr = "2:"+req.attr("err");}
		else	V12 = req.text().charCodeAt(8);
	//Запит кута між векторами U1_U3	
		req.setAttr("cntr",0x10).setText(LLC+F_id+SYS.strFromCharCode( 1, 128, 73, 7, 0, 0)+end);
		tr.messIO(req, "UserProtocol");
		if (req.attr("err").toInt()){V13 = EVAL_INT; tErr = "2:"+req.attr("err");}
		else	V13 = req.text().charCodeAt(8);
		tErr = req.attr("err");
	}
	//Закриття зєднання
	//COMAND_SNRM 
	req.setAttr("cntr",0x53).setText("");
	tr.messIO(req, "UserProtocol");
	tr.start(false, 0);
	
}
//Error set
if(tErr.length) {
	SYS.messDebug("/NIK2303I/TMPL",tr("Error response")+": "+tErr);
	f_err = tErr;
}
else f_err = "0";


ID: ModBusScan
NAME: ModBus scanner
uk#NAME: Сканер ModBus
ru#NAME: Сканер ModBus
DESCR:
ModBus scanner for Coils (1), Input Coils (2), Registers (3), Input Registers (4); in the range [0...65535]. The template useful to examine unknown ModBus devices, scanning their Coils' and Registers' map for detecting the available data addresses. The scanning performs per one item, whether it is a coil or a register, to prevent the data unavailability for strict data accessing devices. The protocol ModBus itself implemented by the OpenSCADA module DAQ.ModBus, together which the template designed to use.

Author: Roman Savochenko <roman@oscada.org>
Total complexity: 0.2 HD
Sponsored by: SVItoVYR Ltd for whole complexity
Version: 1.0.2
License: GPLv2

uk#DESCR:
Сканер ModBus щодо Кілець (1), Вхідних Кілець (2), Регістрів (3), Вхідних Регістрів (4); у діапазоні [0...65535]. Шаблон корисний для вивчення невідомих пристроїв ModBus, скануванням їх мапи Кілець та Регістрів для виявлення наявних адрес даних. Сканування відбувається по одному елементу, чи то кільцю чи регістру, для попередження недоступності даних на пристроях суворого доступу даних. Сам протокол ModBus реалізовано модулем OpenSCADA DAQ.ModBus, разом з яким шаблон і передбачено до використання.

Автор: Роман Савоченко <roman@oscada.org>
Загальна працемісткість: 0.2 ЛД
Спонсорування: ТОВ "СВІТоВИР" на загальну працемісткість
Версія: 1.0.2
Ліцензія: GPLv2

PROGRAM:
JavaLikeCalc.JavaScript
if(f_start) {
	res = "";
	begin = begin_ = end = 0;
	type_ = type;
	//this.attrAdd("type", "", "integer|sel", "0;1;2;3\nCoils (1);Input Coils (2);Registers (3);Input Registers (4)");
	return;
}
if(f_stop) return;

if(type_ != type || begin < begin_)
	begin = max(0,min(65535,begin)), res = "";

for(stTm = SYS.time(); begin < end && begin < 65536 && (SYS.time()-stTm) < lim; begin++) {
	if(type == 0 || type == 1) {
		pdu = SYS.strFromCharCode((type==0)?1:2, begin/256, begin%256, 0, 1);
		rez = this.cntr().messIO(pdu);
		res += begin.toString() + ":\t" + (rez.length?rez:pdu.charCodeAt(2)&0x01) + "\n";
	}
	else {
		pdu = SYS.strFromCharCode((type==2)?3:4, begin/256, begin%256, 0, 1);
		rez = this.cntr().messIO(pdu);
		res += begin.toString() + ":\t" + (rez.length?rez:pdu.charCodeAt(2)*256+pdu.charCodeAt(3))  + "\n";
	}
}
type_ = type, begin_ = begin;


ID: pulsarM
NAME: Pulsar-M
uk#NAME: Пульсар-М
ru#NAME: Пульсар-М
DESCR:
Pulsar-M counters protocol.

Author: Roman Savochenko <roman@oscada.org>
Sponsored: Zubarev Dmitry (IP INTEGRAL<http://kip-i-a.pro>)
Version: 1.0.0
License: GPLv2

PROGRAM:
JavaLikeCalc.JavaScript
//Same request to the device
function req(tr, iaddr, func, data) {
	addr_ = iaddr.toString(10).toInt(16);
	reqId = rand(65535);
	req = Special.FLibSYS.IO("", "", "l");
	req.wr(addr_, "uint32", "b").wr(func, "uint8").wr(data.length+10, "uint8").wr(data.string, "char").wr(reqId, "uint16");
	req.wr(Special.FLibSYS.CRC(req.string), "uint16");
	if(func == 3)	SYS.messInfo("/Pulsar",tr("Request")+": "+SYS.strDecode(req.string,"Bin"," "));
	resp = Special.FLibSYS.IO("", "", "l");
	resp.wr(tr.messIO(req.string),"char");
	while(resp.length && (resp.length < 10 || resp.length < resp.string.charCodeAt(5)) &&
		(tresp=tr.messIO("")).length) resp.wr(tresp,"char");
	//SYS.messInfo("/Pulsar",tr("Response")+": "+SYS.strDecode(resp.string,"Bin"," "));
	//data = resp;
	if(resp.length < 10)							return tr("3:No response or the response is short.");
	resp.pos = 0;
	if(resp.read("uint32",1,"b") != addr_)	return tr("4:Disparity of the request address and the response one.");
	if(resp.read("uint8",1) != func)			return tr("4:Disparity of the request function and the response one.");
	if(resp.read("uint8",1) > resp.length)	return tr("4:Incomplete response.");
	data.string = resp.read("char", resp.length-10);
	if(resp.read("uint16",1) != reqId.toInt())
		return tr("4:Disparity of the request ID and the response one.");
	if(resp.read("uint16",1) != Special.FLibSYS.CRC(resp.string.slice(0,-2)))
		return tr("4:Error CRC.");
	return "0";
}

//Set transport and init
if(f_start) {
	transport_ = transport;
	tr = SYS.Transport.nodeAt(transport,".");
	nChnl_ = 0;
	wrBuf = new Array();
	wrBufW = new Array();
}
if(f_stop) return;

t_err = "0";

if(nChnl != nChnl_) {
	nChnl = max(0, min(32,nChnl));
	for( ; nChnl_ < nChnl; nChnl_++) {
		this.attrAdd("chnl"+nChnl_, tr("Channel")+" "+(nChnl_+1)+": "+tr("value"), "real");
		this.attrAdd("w"+nChnl_, tr("Channel")+" "+(nChnl_+1)+": "+tr("weight"), "real");
		this.attrAdd("avF"+nChnl_, tr("Channel")+" "+(nChnl_+1)+": "+tr("average flow"), "real|ro");
		this.attrAdd("in"+nChnl_, tr("Channel")+" "+(nChnl_+1)+": "+tr("input"), "boolean|ro");
	}
	for( ; nChnl_ > nChnl; nChnl_--) {
		this.attrDel("chnl"+(nChnl_-1));
		wrBuf[nChnl_-1] = EVAL;
		this.attrDel("w"+(nChnl_-1));
		wrBufW[nChnl_-1] = EVAL;
		this.attrDel("avF"+(nChnl_-1));
		this.attrDel("in"+(nChnl_-1));
	}
}
//Check for the transport change and connect
if(!tr || transport != transport_)	{
	transport_ = transport;
	tr = SYS.Transport.nodeAt(transport,".");
}
if(!tr)	t_err = "1:"+tr("Error the output transport '%1'.").replace("%1",transport);
else if(addr < 0 || addr > 99999999)
	t_err = "2:"+tr("The address '%1' is out of the range [0...99999999].").replace("%1",addr.toString());
else {
	//Processing for writing channels and their weights
	for(iCh = 0; iCh < nChnl && !t_err.toInt(); iCh++) {
		//Checking channels to write
		if(!wrBuf[iCh].isEVal() && !(aVl=this["chnl"+iCh].get()).isEVal() && aVl != wrBuf[iCh]) {
			io = Special.FLibSYS.IO("", "", "l");
			io.wr((0x01<<iCh), "uint32");
			io.wr(aVl, "real*8");
			if(!(t_err=req(tr,addr,3,io)).toInt())	wrBuf[iCh] = aVl;
		}
		//Checking weights to write
		if(!wrBufW[iCh].isEVal() && !(aVl=this["w"+iCh].get()).isEVal() && aVl != wrBufW[iCh]) {
			io = Special.FLibSYS.IO("", "", "l");
			io.wr((0x01<<iCh), "uint32");
			io.wr(aVl, "real*4");
			if(!(t_err=req(tr,addr,8,io)).toInt())	wrBufW[iCh] = aVl;
		}
		//Reading channels
		/*io = Special.FLibSYS.IO("", "", "l");
		io.wr((0x01<<iCh), "uint32");
		if(!(t_err=req(tr,addr,1,io)).toInt()) {
			wrBuf[iCh] = io.read("real*8",1);
			this["chnl"+iCh].set(wrBuf[iCh], 0, 0, true);	
		}
		//Reading weights
		io = Special.FLibSYS.IO("", "", "l");
		io.wr((0x01<<iCh), "uint32");
		if(!(t_err=req(tr,addr,7,io)).toInt()) {
			wrBufW[iCh] = io.read("real*4",1);
			this["w"+iCh].set(wrBufW[iCh], 0, 0, true);	
		}
		//Reading average floats
		io = Special.FLibSYS.IO("", "", "l");
		io.wr((0x01<<iCh), "uint32");
		if(!(t_err=req(tr,addr,0x3E,io)).toInt())
			this["avF"+iCh].set(io.read("real*8",1), 0, 0, true);*/
	}

	//Reading for channels, their weights, average floats and inputs
	chMask = 0;
	for(iCh = 0; iCh < nChnl; iCh++)	chMask = chMask | (1<<iCh);

	// Reading channels
	if(!t_err.toInt()) {
		io = Special.FLibSYS.IO("", "", "l");
		io.wr(chMask, "uint32");
		if(!(t_err=req(tr,addr,1,io)).toInt())
			for(iCh = 0; iCh < nChnl; iCh++) {
				wrBuf[iCh] = io.read("real*8",1);
				this["chnl"+iCh].set(wrBuf[iCh], 0, 0, true);	
			}
	}
	// Reading weights
	if(!t_err.toInt()) {
		io = Special.FLibSYS.IO("", "", "l");
		io.wr(chMask, "uint32");
		if(!(t_err=req(tr,addr,7,io)).toInt())
			for(iCh = 0; iCh < nChnl; iCh++) {
				wrBufW[iCh] = io.read("real*4",1);
				this["w"+iCh].set(wrBufW[iCh], 0, 0, true);	
			}
	}
	// Reading average floats
	if(!t_err.toInt()) {
		io = Special.FLibSYS.IO("", "", "l");
		io.wr(chMask, "uint32");
		if(!(t_err=req(tr,addr,0x3E,io)).toInt())
			for(iCh = 0; iCh < nChnl; iCh++)
				this["avF"+iCh].set(io.read("real*8",1), 0, 0, true);
	}
	// Reading for inputs
	if(!t_err.toInt()) {
		io = Special.FLibSYS.IO("", "", "l");
		io.wr(chMask, "uint32");
		if(!(t_err=req(tr,addr,0x19,io)).toInt()) {
			vMask = io.read("uint32", 1);
			for(iCh = 0; iCh < nChnl; iCh++)
				this["in"+iCh].set((vMask&(1<<iCh))?true:false, 0, 0, true);
		}
	}
}

f_err = t_err;


ID: OWEN
NAME: OWEN
DESCR:
OWEN data sources implementation in the OWEN protocol. Implemented wholly in the template for the protocol requesting and for dynamic data model of the OWEN data sources' data with support of the writing and original names of the parameters.

The field "addr" of the items can be wrote positive, for the 8 bit address [0...255], and negative, for the 11 bit address[-2047...0].

Author: Roman Savochenko <roman@oscada.org>, Constantine (IrmIngeneer)
State of the protocol implementing: Client of the protocol for reading and writing the specified PLC properties.
Total complexity: 0.5 HD
Actual issues: The undocumented behaviour:
  - МВ110-8А responds error 0x31 for reading "in-t": >1003023331932DCB43 <1010932D4791;
  - and error 0x34 for it writing: >1003023334932D2A42 <1001932D0BEDBC.
Version: 0.8.1
License: GPLv2

PROGRAM:
JavaLikeCalc.JavaScript
function hash(data, isName) {
	for(CRC = 0, i = 0; i < data.length; i++) {
		b = data.charCodeAt(i);
		for(j = 0; j < ((isName==true)?7:8); j++, b = b << 1)
			CRC = ((b^(CRC>>8)&0x80)?(CRC<<1)^0x8F57:CRC<<1) & 0xFFFF;
	}
	return CRC;
}

function nmHash(name) {
	for(srcF = name + "    ", hashF = "", iV = 0; iV < srcF.length; iV++) {
		tVl = srcF[iV]; tVl2 = srcF.charCodeAt(iV);
		if(tVl == "." && iV > 0)	{ hashF = hashF.slice(0,-1)+SYS.strFromCharCode(hashF.charCodeAt(hashF.length-1)+1); continue; }
		if(tVl2 >= 0x30 && tVl2 <= 0x39)		tVl = tVl2-0x30;
		else if(tVl2 >= 0x41 && tVl2 <= 0x5A)	tVl = tVl2-0x41+10;
		else if(tVl2 >= 0x61 && tVl2 <= 0x7A)	tVl = tVl2-0x61+10;
		else if(tVl == "-")	tVl = 10+26;
		else if(tVl == "_")	tVl = 10+26+1;
		else if(tVl == "/")	tVl = 10+26+2;
		else if(tVl == " ")	tVl = 10+26+3;
		else break;
		hashF += SYS.strFromCharCode(tVl*2);
	}
	if(iV < name.length || hashF.length < 4)	return -1;
	for(rez = "", iV = 0; iV < 4; iV++)
		rez += SYS.strFromCharCode(hashF.charCodeAt(iV)*2);

	//SYS.messDebug("/OWEN", "func="+name+"; code="+SYS.strDecode(rez));

	return hash(rez, true);
}

//Same request to the device
//  addr - negative for 11 bit type
function req(tr, addr, data) {
	if(addr < -2047 || addr > 255)	return "1:"+tr("Address out of the range [-2047...255].");
	req = SYS.strFromCharCode((addr>=0)?abs(addr):abs(addr)>>3, ((addr>=0)?0:abs(addr<<5))|((data.length>2)?data.length-2:0x10)) + data;

	// Appending CRC
	CRC = hash(req);
	req += SYS.strFromCharCode(CRC>>8, CRC&255);

	SYS.messDebug("/OWEN", "req="+SYS.strDecode(req));

	// Converting to ASCII
	for(reqASCII = "", i = 0; i < req.length; i++)
		reqASCII += SYS.strFromCharCode((req.charCodeAt(i)>>4)+71, (req.charCodeAt(i)&0x0F)+71);
	req = "#" + reqASCII + "\r";

	// Sending the request and getting response
	for(resp = tr.messIO(req); resp[resp.length-1] != "\r" && (respTail=tr.messIO("")).length; )
		resp += respTail;

	// Processing the response
	if(resp.length < req.length || resp[resp.length-1] != "\r" || resp[0] != "#" || (resp.length%2) != 0)
		return "10:"+tr("Wrong or no response.");

	//SYS.messDebug("/OWEN", "resp="+resp);

	resp = resp.slice(1, resp.length-1);

	// Converting to binary
	for(respBin = "", b = 0, i = 0, fullB = false; i < resp.length; i++, fullB = !fullB) {
		b += resp.charCodeAt(i) - 71;
		if(fullB) { respBin += SYS.strFromCharCode(b); b = 0; } else b *= 16;
	}
	resp = respBin;

	SYS.messDebug("/OWEN", "resp="+SYS.strDecode(resp));

	// Checking for CRC
	CRC = hash(resp.slice(0,-2));
	if(CRC != ((resp.charCodeAt(resp.length-2)<<8)+resp.charCodeAt(resp.length-1)))
		return "11:"+tr("Error CRC.");

	if(resp.charCodeAt(1) != (resp.length-6))
		return "12:"+tr("The data size is not equal to pointed one.");
	else if(resp.slice(2,4) != data.slice(0,2) && resp.charCodeAt(2,"UTF-16BE") != nmHash("n.Err"))
		return "21:Unpaired function in the response.";

	data = resp.slice(2, resp.length-2);
	//if(data.length < 3)	return "49:"+tr("Data size error.");

	return "0";
}

//Set transport and init
if(f_start) {
	dt = new Object();
	items_ = "";
	transport_ = transport;
	tr = SYS.Transport.nodeAt(transport,".");

	t_infW = ""; infWHoldTm = 0;
}
if(f_stop) return;

//Parsing the items to set and to create the user attributes
if(items != items_) {
	items_ = items;
	// Mark of checking to deletion needs
	for(var iDt in dt)	dt[iDt].mark = false;
	// Appending/Updating present ones
	for(itOff = 0; (sIt=items.parseLine(0,itOff)).length; ) {
		if(sIt[0] == "#")	continue;
		off1 = 0;
		itO = new Object();
		itO.addr = sIt.parse(0, ":", off1).toInt();
		itO.func = sIt.parse(0, ":", off1);
		itO.tp = sIt.parse(0, ":", off1);
		itO.md = sIt.parse(0, ":", off1);
		itO.id = sIt.parse(0, ":", off1);
		itO.nm = sIt.slice(off1);
		if(!itO.nm.length)	itO.nm = itO.id.length ? itO.id : itO.func;
		if(!itO.id.length)	itO.id = itO.func.replace(new RegExp("[.]"), "_");
		SYS.messDebug("/OWEN", "id="+itO.id);
		if(itO.tp == "u" || itO.tp == "i") {
			wTp = "integer";
			itO.sz = itO.tp.slice(1).toInt();
			itO.sz = (itO.sz?itO.sz:16)/8;
			if(!(itO.sz==1||itO.sz==2||itO.sz==4))	continue; 
		}
		else if(itO.tp == "s")	wTp = "string";
		else if(itO.tp == "f")	wTp = "real";
		else continue;
		itO.rd = (itO.md.indexOf("r") >= 0); itO.wr = (itO.md.indexOf("w") >= 0);
		if(!itO.wr)	wTp += "|ro";
		if((itO.funcH=nmHash(itO.func)) < 0)	continue;
		// Apending
		dt[itO.id] = itO;
		if(itO.rd || itO.wr) {
			this.attrAdd(itO.id, itO.nm, wTp);
			if(itO.wr)	itO.val = this[itO.id].get();
			itO.mark = true;
			//SYS.messDebug("/OWEN", "itO="+itO.id+"; tmpAddr="+tmpAddr+"; addr="+itO.addr);
		}
	}
	// Check, remove item and set to EVAL the attribute
	for(var iDt in dt) {
		if(dt[iDt].mark)	continue;
		this[dt[iDt].id].set(EVAL, 0, 0, true);	//If the attribute locked
		this.attrDel(dt[iDt].id);
		delete dt[iDt];
	}
}

t_err = "0";

//Check for the transport change and connect
if(!tr || transport != transport_)	{
	transport_ = transport;
	tr = SYS.Transport.nodeAt(transport,".");
}
if(!tr)	t_err = "1:"+tr("Error the output transport '%1'.").replace("%1",transport);
else {
	t_inf = "";
	if(infWHoldTm && SYS.time() > infWHoldTm)	t_infW = "", infWHoldTm = 0;
	
	//The parameters processing
	for(var iDt in dt) {
		itO = dt[iDt];
		if(!t_err.toInt()) {
			SYS.messDebug("/OWEN", "iDt="+iDt);

			// Writing
			if(itO.wr && !(tVl=this[itO.id].get()).isEVal() && tVl != itO.val) {
				data = SYS.strFromCharCode(itO.funcH>>8, itO.funcH&0xFF);
				if(itO.tp == "f") {
					tVl2 = tVl3 = 0;
					Special.FLibSYS.floatSplitWord(tVl, tVl2, tVl3);
					data += SYS.strFromCharCode(tVl3>>8, tVl3&0xFF, tVl2>>8) + ((tVl2&0xFF)?SYS.strFromCharCode(tVl2&0xFF):"");
				}
				else if(itO.tp == "u" || itO.tp == "i") {
					for(tVl2 = SYS.strFromCharCode(tVl&0xFF), tVl = tVl>>8; tVl; tVl = tVl>>8)
						tVl2 = SYS.strFromCharCode(tVl&0xFF) + tVl2;
					data += tVl2;
				}
				else if(itO.tp == "s")
					for(iV = tVl.length-1; iV >= 0; iV--)	data += tVl[iV];

				if(!(t_err=req(tr,itO.addr,data)).toInt()) {
					if(data.charCodeAt(0,"UTF-16BE") == nmHash("n.Err")) {
						t_infW += (t_infW.length?"; ":": ")+itO.nm+":nErr=0x"+data.charCodeAt(2).toString(16);
						infWHoldTm = SYS.time()+10;
					} else itO.val = tVl;
				}
			}

			// Reading
			data = SYS.strFromCharCode(itO.funcH>>8, itO.funcH&0xFF);
			if(itO.rd && !(t_err=req(tr,itO.addr,data)).toInt()) {
				if(data.charCodeAt(0,"UTF-16BE") == nmHash("n.Err") && itO.funcH != nmHash("n.Err")) {
					t_inf += (t_inf.length?"; ":": ")+itO.nm+":nErr=0x"+data.charCodeAt(2).toString(16);
					this[itO.id].set(EVAL, 0, 0, true); itO.val = EVAL;
				}
				else {
					data = data.slice(2);
					if(itO.tp == "f") {
						if(data.length == 1)
							tVl = EVAL, t_inf += (t_inf.length?"; ":": ")+itO.nm+":err=0x"+data.charCodeAt(0).toString(16);
						else if(data.length >= 3)
							tVl = Special.FLibSYS.floatMergeWord(
								data.charCodeAt(2)*256+((data.length < 4)?0:data.charCodeAt(3)),
								data.charCodeAt(0)*256+data.charCodeAt(1));
						else tVl = EVAL;
						this[itO.id].set(tVl, 0, 0, true); itO.val = tVl;
					}
					else if(itO.tp == "u" || itO.tp == "i") {
						for(tVl = 0, iV = 0; iV < data.length; iV++)
							tVl = (tVl<<8) | data.charCodeAt(iV);
						this[itO.id].set(tVl, 0, 0, true); itO.val = tVl;
						//SYS.messDebug("/OWEN", "Integer data="+SYS.strDecode(data)+"; Sz="+itO.sz);
					}
					else if(itO.tp == "s")	{
						for(tVl = "", iV = 0; iV < data.length; iV++)	tVl = data[iV] + tVl;
						this[itO.id].set(tVl, 0, 0, true);	 itO.val = tVl;
					}
					continue;
				}
			}
		}
		this[itO.id].set(EVAL, 0, 0, true); itO.val = EVAL;
	}
}

f_err = t_err;
if(!f_err.toInt())	f_err += t_inf + (t_infW.length?" "+tr("Write")+t_infW:"");


ID: DCON_Prt
NAME: DCON Protocol + Input AI
DESCR:
Input and output parts of the protocol DCON implementation with the input part designed for typical AI modules at up to 20 channels. The protocol DCON client part also implemented by the OpenSCADA module DAQ.DCON.

The DCON commands are supported: #AA

Author: Roman Savochenko <roman@oscada.org>
Version: 1.0.1
License: GPLv2

PROGRAM:
JavaLikeCalc.JavaScript
if(f_start)	io = tr = EVAL;

function CRC( inS ) {
	sumV = 0;
	for(i = 0; i < inS.length; i++) sumV += inS.charCodeAt(i);

	return sumV&0xFF;
}

//---------------------------------------
//Output request form of the UserProtocol
//---------------------------------------
//<ReqSymb addr="{toAddr}" err="{err}" CRC="{CRC}">{req}</ReqSymb> - tag of the output message
//  ReqSymb - symbol of the request type into the tag name, like to: '#', '@', etc;
//  toAddr - remote host address [0...240];
//  CRC - sign [0,1] of using CRC;
//  req - data of the request and response;
//  err - sets for the request result.
if(!tr.isEVal() && !io.isEVal() && io.attr("ProtIt").length) {
	io.setAttr("err", "0");

	req = io.name().slice(0,1) + io.attr("addr").toInt().toString(16,2) + io.text();
	if(io.attr("CRC").toInt())
		req += (CRC(req)&0xFF).toString(16,2);
	req += "\r";

	//Sending the request
	resp = tr.messIO(req);
	while(resp.length && resp[resp.length-1] != "\r")
		if((tresp=tr.messIO("")).length) resp += tresp;
		else break;

	//Analysis of the response
	if(io.attr("CRC").toInt()) {
		if(resp.length < 4 || resp[resp.length-1] != "\r")
		{ io.setAttr("err","10:"+tr("Error or no response.")); return; }
		//Checking the response to the integrity (CRC)
		if(CRC(resp.slice(0,-3)) != resp.slice(-3,-1).toInt(16))
		{ io.setAttr("err","11:"+tr("CRC error.")); return; }
	}
	else if(resp.length < 2 || resp[resp.length-1] != "\r")
	{ io.setAttr("err","10:"+tr("Error or no response.")); return; }
	if(resp[0] != ">") { io.setAttr("err","12:"+resp[0]+":"+tr("DCON error.")); return; }

	//Returning the result
	io.setText(resp.slice(1,(io.attr("CRC").toInt()?-3:-1)));

	return;
}

//---------------------------------------------
//Input requests processing of the UserProtocol
//---------------------------------------------
//Testing the request for completity
if(request.length < 4 || request[request.length-1] != "\r") {
	if(request.length > 10) request = "";
	return true;
}
addr = max(0, min(240,addr));
n = max(1, min(20,n));
req = request; request = "";

//SYS.messInfo("DCON/in", "TEST 01: "+req);

//Checking the request for the integrity (CRC) and the address
if((enCRC && CRC(req.slice(0,-3)) != req.slice(-3,-1).toInt(16)) || !(addr == 0 || req.slice(1,3).toInt(16) == addr))
	return true;

//Analysis the request and the response preparing
if(req[0] == "#") {	//Commands #AA
	answer = ">";
	for(iA = 0; iA < n; iA++)
		answer += ((tVl=arguments["ai"+iA]).isEVal()?0:tVl).toFixed(3,7,true);
} else answer = "?";	//return true;

//Finishing the response
if(enCRC) answer += (CRC(answer)&0xFF).toString(16,2);
answer += "\r";

return true;


ID: DCON_Prt_DI
NAME: DCON Protocol + Input DI
DESCR:
Input and output parts of the protocol DCON implementation with the input part designed for typical DI modules at up to 32 channels. The protocol DCON client part also implemented by the OpenSCADA module DAQ.DCON.

The DCON commands are supported: @AA, $AA6

Author: Roman Savochenko <roman@oscada.org>
Version: 1.0.1
License: GPLv2

PROGRAM:
JavaLikeCalc.JavaScript
if(f_start)	io = tr = EVAL;

function CRC( inS ) {
	sumV = 0;
	for(i = 0; i < inS.length; i++) sumV += inS.charCodeAt(i);

	return sumV&0xFF;
}

//---------------------------------------
//Output request form of the UserProtocol
//---------------------------------------
//<ReqSymb addr="{toAddr}" err="{err}" CRC="{CRC}">{req}</ReqSymb> - tag of the output message
//  ReqSymb - symbol of the request type into the tag name, like to: '#', '@', etc;
//  toAddr - remote host address [0...240];
//  CRC - sign [0,1] of using CRC;
//  req - data of the request and response;
//  err - sets for the request result.
if(!tr.isEVal() && !io.isEVal() && io.attr("ProtIt").length) {
	io.setAttr("err", "0");

	req = io.name().slice(0,1) + io.attr("addr").toInt().toString(16,2) + io.text();
	if(io.attr("CRC").toInt())
		req += (CRC(req)&0xFF).toString(16,2);
	req += "\r";

	//Sending the request
	resp = tr.messIO(req);
	while(resp.length && resp[resp.length-1] != "\r")
		if((tresp=tr.messIO("")).length) resp += tresp;
		else break;

	//Analysis of the response
	if(io.attr("CRC").toInt()) {
		if(resp.length < 4 || resp[resp.length-1] != "\r")
		{ io.setAttr("err","10:"+tr("Error or no response.")); return; }
		//Checking the response to the integrity (CRC)
		if(CRC(resp.slice(0,-3)) != resp.slice(-3,-1).toInt(16))
		{ io.setAttr("err","11:"+tr("CRC error.")); return; }
	}
	else if(resp.length < 2 || resp[resp.length-1] != "\r")
	{ io.setAttr("err","10:"+tr("Error or no response.")); return; }
	if(resp[0] != ">") { io.setAttr("err","12:"+resp[0]+":"+tr("DCON error.")); return; }

	//Returning the result
	io.setText(resp.slice(1,(io.attr("CRC").toInt()?-3:-1)));

	return;
}

//---------------------------------------------
//Input requests processing of the UserProtocol
//---------------------------------------------
//Testing the request for completity
if(request.length < 4 || request[request.length-1] != "\r") {
	if(request.length > 10) request = "";
	return true;
}
addr = max(0, min(240,addr));
n = max(1, min(32,n));
req = request; request = "";

//SYS.messInfo("DCON/in", "TEST 01: "+req);

//Checking the request for the integrity (CRC) and the address
if((enCRC && CRC(req.slice(0,-3)) != req.slice(-3,-1).toInt(16)) || !(addr == 0 || req.slice(1,3).toInt(16) == addr))
	return true;

//Analysis the request and the response preparing
if(req[0] == "@" || (req[0] == "$" && req[3] == "6")) {	//Commands @AA and $AA6
	for(ib = 0; ib < n; ib++) {
		if(ib%8 == 0)	tVl = 0;
		tVl += ((arguments["di"+ib] == true)?1:0) << (ib%8);
		if(ib%8 == 7 || (ib+1) == n)	answer = tVl.toString(16,2) + answer;
	}
	if(req[0] == "$")	answer += "00";
	answer = "!" + answer;
} else answer = "?";	//return true;


//Finishing the response
if(enCRC) answer += (CRC(answer)&0xFF).toString(16,2);
answer += "\r";

return true;


ID: DCON_Prt_AO
NAME: DCON Protocol + Input AO
DESCR:
Input and output parts of the protocol DCON implementation with the input part designed for typical AO modules at up to 8 channels. The protocol DCON client part also implemented by the OpenSCADA module DAQ.DCON.

The DCON commands are supported: $AA8N, #AAN{Data}

Author: Roman Savochenko <roman@oscada.org>
Version: 1.0.1
License: GPLv2

PROGRAM:
JavaLikeCalc.JavaScript
if(f_start)	io = tr = EVAL;

function CRC( inS ) {
	sumV = 0;
	for(i = 0; i < inS.length; i++) sumV += inS.charCodeAt(i);

	return sumV&0xFF;
}

//---------------------------------------
//Output request form of the UserProtocol
//---------------------------------------
//<ReqSymb addr="{toAddr}" err="{err}" CRC="{CRC}">{req}</ReqSymb> - tag of the output message
//  ReqSymb - symbol of the request type into the tag name, like to: '#', '@', etc;
//  toAddr - remote host address [0...240];
//  CRC - sign [0,1] of using CRC;
//  req - data of the request and response;
//  err - sets for the request result.
if(!tr.isEVal() && !io.isEVal() && io.attr("ProtIt").length) {
	io.setAttr("err", "0");

	req = io.name().slice(0,1) + io.attr("addr").toInt().toString(16,2) + io.text();
	if(io.attr("CRC").toInt())
		req += (CRC(req)&0xFF).toString(16,2);
	req += "\r";

	//Sending the request
	resp = tr.messIO(req);
	while(resp.length && resp[resp.length-1] != "\r")
		if((tresp=tr.messIO("")).length) resp += tresp;
		else break;

	//Analysis of the response
	if(io.attr("CRC").toInt()) {
		if(resp.length < 4 || resp[resp.length-1] != "\r")
		{ io.setAttr("err","10:"+tr("Error or no response.")); return; }
		//Checking the response to the integrity (CRC)
		if(CRC(resp.slice(0,-3)) != resp.slice(-3,-1).toInt(16))
		{ io.setAttr("err","11:"+tr("CRC error.")); return; }
	}
	else if(resp.length < 2 || resp[resp.length-1] != "\r")
	{ io.setAttr("err","10:"+tr("Error or no response.")); return; }
	if(resp[0] != ">") { io.setAttr("err","12:"+resp[0]+":"+tr("DCON error.")); return; }

	//Returning the result
	io.setText(resp.slice(1,(io.attr("CRC").toInt()?-3:-1)));

	return;
}

//---------------------------------------------
//Input requests processing of the UserProtocol
//---------------------------------------------
//Testing the request for completity
if(request.length < 4 || request[request.length-1] != "\r") {
	if(request.length > 10) request = "";
	return true;
}
addr = max(0, min(240,addr));
req = request; request = "";

//SYS.messInfo("DCON/in", "TEST 01: "+req);

//Checking the request for the integrity (CRC) and the address
if((enCRC && CRC(req.slice(0,-3)) != req.slice(-3,-1).toInt(16)) || !(addr == 0 || req.slice(1,3).toInt(16) == addr))
	return true;

//Analysis the request and the response preparing
if(req[0] == "$" && req[3] == "8") {	//Command $AA8N to read back the output value
	answer = "!";
	n = req.slice(4,5).toInt(16);
	answer += req.slice(1,3) + ((tVl=arguments["ao"+n]).isEVal()?0:tVl).toFixed(3,7,true);
}
else if(req[0] == "#" && req.length >= 10) {	//Command #AAN{Data} to write the output
	n = req.slice(3,4).toInt(16);
	arguments["ao"+n] = req.slice(4,(enCRC?-3:-1)).toReal();
	answer = ">";
}
else answer = "?";	//return true;

//Finishing the response
if(enCRC) answer += (CRC(answer)&0xFF).toString(16,2);
answer += "\r";

return true;


ID: DCON_Prt_DO
NAME: DCON Protocol + Input DO
DESCR:
Input and output parts of the protocol DCON implementation with the input part designed for typical DO modules at up to 32 channels. The protocol DCON client part also implemented by the OpenSCADA module DAQ.DCON.

The DCON commands are supported: @AA, @AA{Data}

Author: Roman Savochenko <roman@oscada.org>
Version: 1.0.1
License: GPLv2

PROGRAM:
JavaLikeCalc.JavaScript
if(f_start)	io = tr = EVAL;

function CRC( inS ) {
	sumV = 0;
	for(i = 0; i < inS.length; i++) sumV += inS.charCodeAt(i);

	return sumV&0xFF;
}

//---------------------------------------
//Output request form of the UserProtocol
//---------------------------------------
//<ReqSymb addr="{toAddr}" err="{err}" CRC="{CRC}">{req}</ReqSymb> - tag of the output message
//  ReqSymb - symbol of the request type into the tag name, like to: '#', '@', etc;
//  toAddr - remote host address [0...240];
//  CRC - sign [0,1] of using CRC;
//  req - data of the request and response;
//  err - sets for the request result.
if(!tr.isEVal() && !io.isEVal() && io.attr("ProtIt").length) {
	io.setAttr("err", "0");

	req = io.name().slice(0,1) + io.attr("addr").toInt().toString(16,2) + io.text();
	if(io.attr("CRC").toInt())
		req += (CRC(req)&0xFF).toString(16,2);
	req += "\r";

	//Sending the request
	resp = tr.messIO(req);
	while(resp.length && resp[resp.length-1] != "\r")
		if((tresp=tr.messIO("")).length) resp += tresp;
		else break;

	//Analysis of the response
	if(io.attr("CRC").toInt()) {
		if(resp.length < 4 || resp[resp.length-1] != "\r")
		{ io.setAttr("err","10:"+tr("Error or no response.")); return; }
		//Checking the response to the integrity (CRC)
		if(CRC(resp.slice(0,-3)) != resp.slice(-3,-1).toInt(16))
		{ io.setAttr("err","11:"+tr("CRC error.")); return; }
	}
	else if(resp.length < 2 || resp[resp.length-1] != "\r")
	{ io.setAttr("err","10:"+tr("Error or no response.")); return; }
	if(resp[0] != ">") { io.setAttr("err","12:"+resp[0]+":"+tr("DCON error.")); return; }

	//Returning the result
	io.setText(resp.slice(1,(io.attr("CRC").toInt()?-3:-1)));

	return;
}

//---------------------------------------------
//Input requests processing of the UserProtocol
//---------------------------------------------
//Testing the request for completity
if(request.length < 4 || request[request.length-1] != "\r") {
	if(request.length > 10) request = "";
	return true;
}
addr = max(0, min(240,addr));
n = max(1, min(32,n));
req = request; request = "";

//SYS.messInfo("DCON/in", "TEST 01: "+req);

//Checking the request for the integrity (CRC) and the address
if((enCRC && CRC(req.slice(0,-3)) != req.slice(-3,-1).toInt(16)) || !(addr == 0 || req.slice(1,3).toInt(16) == addr))
	return true;
req = req.slice(0, (enCRC?-3:-1));

//Analysis the request and the response preparing
if(req[0] == "@" && req.length == 3) {	//Commands @AA
	for(ib = 0; ib < n; ib++) {
		if(ib%8 == 0)	tVl = 0;
		tVl += ((arguments["do"+ib] == true)?1:0) << (ib%8);
		if(ib%8 == 7 || (ib+1) == n)	answer = tVl.toString(16,2) + answer;
	}
	answer = ">" + answer;
}
else if(req[0] == "@" && req.length > 3) {	//Commands @AA{Data}
	for(iB = req.length-2, iC = 0; iB >= 3; iB -= 2) {
		tVl = req.slice(iB, iB+2).toInt(16);
		for(ib = 0; ib < 8; ib++, iC++)
			arguments["do"+iC] = tVl&(1<<ib);
	}
	answer = ">";
}
else answer = "?";	//return true;

//Finishing the response
if(enCRC) answer += (CRC(answer)&0xFF).toString(16,2);
answer += "\r";

return true;


ID: DNP3
NAME: Distributed Network Protocol 3
DESCR:
Distributed Network Protocol 3 (DNP3) is a set of communications protocols used between components in process automation systems. Its main use is in utilities such as electric and water companies. Usage in other industries is not common. It was developed for communications between various types of data acquisition and control equipment. Competing standards include the older Modbus protocol and the newer IEC 61850 protocol and IEC 61870.

The template implements currently for the client, which uses the followed functions: Confirm (0x00), Read (0x01), Write (0x02), Enable (0x14) and Disable (0x15) Spontaneous Messages.

And which implements and tested for the followed point-oriented objects (data types):
- 1.[2] — Binary Input [with status]
- 2.[1] — Binary Input Changed [w/o time]
- 3.[2] — Double-bit Input [with status]
- 4.[1] — Double-bit Input Changed [w/o time]
- 10.[2] — Binary Output (reading back and used to write also) [with status]
- 20,21.[1] — Binary Counter (Typical,Frozen) [32-Bit]
- 22,23.[1] — Binary Counter Changed (Typical,Frozen) [32-Bit w/o time]
- 30.[1,5] — Analog Input [32-bit integer value with flag, 32-bit floating point value with flag]
- 32.[7] — Analog Input Changed [32-bit floating point value with flag and event time]
- 40.[1] — Analog Output (reading back and used to write also) [32-bit integer value with flag]
- 50 — Time and Date (just passed and not read) [indexed absolute time and long interval]
- 60.[1,2,3,4] — Classes [0,1,2,3]
- 80.[1] — Device [Restart 7=Off(0x01)]
- 110.[1] — Octet String (just passed and not read) [Sized by variation]

Considering the purpose and the application area, the protocol does not provide the direct determination of the requested data and the device, that implements it, provides all available ones upon request for the Class 0 data, after which only changes are requested for the Classes 1, 2, 3.

All received and controlled data is accumulated in an object of the attribute "items" for further control as an object in a table of the widget "Main.objProps", according to the complex object definition.

For standard control over parameter attributes, including archiving, it is possible to define the necessary data to create a separate representative attribute for them, which is described in the attribute "itemsSet", where they can be defined individually, with a semantic identifier and name, or in a range named by a template. The data in the attribute "itemsSet" is defined by records in the format ai|ao|cnt|di|do:{pnt}[-{endPnt}][:a[:{NameBase}]], where:
- ai|ao|cnt|di|do — data type, where:
  - "ai" — analog inputs, transmitted by the functions 30 and 32;
  - "ao" — analog outputs, transmitted by the function 40;
  - "cnt" — counters, transmitted by the functions 20, 21, 22, 23; so Typical and Frozen counters is in one space;
  - "di" — discrete inputs, transmitted by the functions 1, 2, 3, 4; so Binary Input and Double-bit Input is in one space;
  - "do" — discrete outputs, transmitted by the function 10.
- {pnt} — point number of the range begin;
- {endPnt} — the range end (the last point number);
- a — sign of creating the representative attribute for the parameter or the parameters group;
- {NameBase} — naming base of the attributes.

Examples of the parameters definition, rows of the attribute "itemsSet":
- ai:0-9:a — analog inputs in the points range [0...9] with forming the attributes;
- ao:0-9:a — analog outputs in the points range [0...9] with forming the attributes;
- di:0-9:a — discrete inputs in the points range [0...9] with forming the attributes;
- do:0-9:a — discrete outputs in the points range [0...9] with forming the attributes;
- cnt:0-9:a — counters in the points range [0...9] with forming the attributes.

Author: Roman Savochenko <roman@oscada.org>
Total complexity: 2.0 HD
Sponsored by: Hadi Ramezani and Hossein Malakooti for whole complexity
Version: 0.8.1
License: GPLv2

PROGRAM:
JavaLikeCalc.JavaScript
function CRC( inSeq ) { return Special.FLibSYS.CRC(inSeq, 16, 0x3D65, 0, true, true, -1); }

function inVal(aId, aVal, QLT, wr) {
	if(!QLT.isEVal() && (!(QLT&0x01) || (QLT&0x1E)))	aVal = EVAL;
	if(wr.isEVal())	wr = false;
	if(items[aId].isEVal()) {
		items[aId] = itW = new Object();
		itW.descr = aId;
		itW.wr = wr; itW.alarm = 0;
	} else itW = items[aId];
	itW.val = aVal;
	if((aO=this[aId])) {
		aO.set(aVal, 0, 0, true);
		if(itW.wr) oAVals[aId] = aVal;
	}
}

//Forming of the message and placing it to the output buffer
function mess( func, objs, ac ) {
	if(ac.isEVal())	{
		ac = 0x80 | 0x40 | (ctx.appSeq&0xF);	//FIR, FIN, Sequence
		ctx.reqToResp = ctx.appSeq.toString()+":"+func;
		if(ctx.appSeq >= 15)	ctx.appSeq = 0;	else ctx.appSeq++;
	} 
	aMess = SYS.strFromCharCode(ac, func) + objs;
	//Splitting the application message to the transport messages,
	//		limited in the length in 255 symbols without CRC
	for(off = 0; off < aMess.length; ) {
		trMess = aMess.slice(off, off+min(255-6,aMess.length-off));
		trMess = SYS.strFromCharCode(((off==0)?0x80:0)|((off+trMess.length)>=aMess.length?0x40:0)|(ctx.trSeq&0x3F)) +		//FIR, FIN, Sequence
			trMess;
		if(ctx.trSeq >= 63)	ctx.trSeq = 0;	else ctx.trSeq++;
		off += trMess.length;

		//Splitting the transport message to the data chunks,
		//		limited in 16 symbols and appending CRC
		for(mess = "", chOff = 0; chOff < trMess.length; chOff += 16) {
			tVl = trMess.slice(chOff, chOff+min(16,trMess.length-chOff));
			mess += tVl + SYS.strFromCharUTF("UTF-16",CRC(tVl));
		}

		//Appending the transport message header and it CRC
		tVl = SYS.strFromCharCode(0x05, 0x64, (trMess.length+5), 0x80|0x40|0x4) +	//DIR, PRM, Unconfirmed User Data (4) ????
				SYS.strFromCharUTF("UTF-16", dest, src);
		mess = tVl + SYS.strFromCharUTF("UTF-16",CRC(tVl)) + mess;
		ctx.out += mess;				//Buffering
		//tr.messIO(mess, 0, 0);	//Just direct writing per one message
	}
}

function processIn( ) {
	t_err = "";
	//Parse for packages in general - the transport layer
	for(waitSz = 0; ctx.in.length; ctx.in = ctx.in.slice(waitSz)) {
		// Checking the header entirety
		if((ctx.in.length >= 3 && (ctx.in.charCodeAt(0,"UTF-16") != 0x6405 || (dataSz=ctx.in.charCodeAt(2)) < 8)) ||
				(ctx.in.length >= 10 && CRC(ctx.in.slice(0,8)) != ctx.in.charCodeAt(8,"UTF-16"))) {
			SYS.messDebug("/DNP3",tr("Wrong or CRC-error sequence, rejected")+": "+SYS.strDecode(ctx.in,"Bin"," "));
			ctx.in = "";
			break;
		}
		waitSz = 10 + floor((dataSz-5)/16)*18 + ((tVl=(dataSz-5)%16)?tVl+2:0);
		if(ctx.in.length < 13 || ctx.in.length < waitSz)	break;	//Not full, waiting

		SYS.messDebug("/DNP3",tr("Good input sequence")+": "+SYS.strDecode(ctx.in.slice(0,waitSz),"Bin"," "));

		if(ctx.in.charCodeAt(4,"UTF-16") != src || ctx.in.charCodeAt(6,"UTF-16") != dest) {
			SYS.messDebug("/DNP3",tr("Foreign package, rejected")+": "+SYS.strDecode(ctx.in.slice(waitSz),"Bin"," "));
			continue;
		}

		// Getting the data chunks
		for(data = "", off = 10, iCh = 0; off < waitSz; off += 18, iCh++) {
			chSz = min(waitSz, off+18) - 2;
			if(CRC((tVl=ctx.in.slice(off,chSz))) != ctx.in.charCodeAt(chSz,"UTF-16"))	break;
			data += tVl;
		}
		if(off < waitSz) {
			SYS.messDebug("/DNP3",tr("CRC error in chunk %1, rejected").replace("%1",iCh.toString()));
			continue;
		}

		// Control of the transport packages sequence
		//  First
		if((tc=data.charCodeAt(0))&0x40) {
			ctx.inAMess = data;
			if(!(tc&0x80)) {							//Not Final
				if(ctx.firSeq >= 0 && (((wSeq=ctx.firSeq+1)>=64)?0:wSeq) != (tc&0x3F))	SYS.messDebug("/DNP3",tr("Broken sequence, rejected"));
				ctx.firSeq = tc&0x3F;
			}
		}
		//  Final or Pass
		else if(ctx.firSeq < 0 || (((wSeq=ctx.firSeq+1)>=64)?0:wSeq) != (tc&0x3F)) {	//Broken sequence
			SYS.messDebug("/DNP3",tr("Broken sequence, rejected"));
			ctx.firSeq = -1;
		}
		else if(ctx.firSeq >= 0) {																		//Good sequence
			ctx.inAMess += data.slice(1);
			ctx.firSeq = (tc&0x80) ? -1 : (tc&0x3F);	//Not Final
		}

		// Process of the reassigned application message
		if(ctx.inAMess.length && (tc&0x80)) {
			am = ctx.inAMess.slice(1), ctx.inAMess = "";	//Get the application message
			ac = am.charCodeAt(0);
			SYS.messDebug("/DNP3", "Input application message: "+SYS.strDecode(am,"Bin"," "));

			//  Checking and disabling the Spontaneous Messages
			if(am.charCodeAt(1) == 0x82 && !ctx.spontEn)	mess(0x15, SYS.strFromCharCode(0x3C,0x02,0x06,0x3C,0x03,0x06,0x3C,0x04,0x06));
			//  Confirmation
			if(ac&0x20)	mess(0x00, "", 0x80|0x40|(ac&0x1F));
			//  Processing the response package
			if((am.charCodeAt(1) == 0x81 && ctx.reqToResp.length && ctx.reqToResp.toInt() == (ac&0x0F)) || am.charCodeAt(1) == 0x82) {
				intInd = am.charCodeAt(2,"UTF-16BE");
				if(intInd&0x8000) t_err += tr("Device Restart")+"; ";
				if(intInd&0x4000) t_err += tr("Device Trouble")+"; ";
				if(intInd&0x2000) t_err += tr("Digital Outputs in Local")+"; ";
				if(intInd&0x1000) t_err += tr("Time Sync Required")+"; ";
				if(intInd&0x0800) t_err += tr("Class 3 Data Available")+"; ";
				if(intInd&0x0400) t_err += tr("Class 2 Data Available")+"; ";
				if(intInd&0x0200) t_err += tr("Class 1 Data Available")+"; ";
				if(intInd&0x0020) t_err += tr("Configuration Corrupt")+"; ";
				if(intInd&0x0010) t_err += tr("Operation Already Executing")+"; ";
				if(intInd&0x0008) t_err += tr("Event Buffer Overflow")+"; ";
				if(intInd&0x0004) t_err += tr("Parameters Invalid or Out of Range")+"; ";
				if(intInd&0x0002) t_err += tr("Requested Objects Unknown")+"; ";
				if(intInd&0x0001) t_err += tr("Function Code not implemented")+"; ";
				//respToF = ctx.reqToResp.parse(1,":").toInt();
				ctx.reqToResp = "";	//The propper response came
				if(intInd&0x8000)	mess(0x2, SYS.strFromCharCode(0x50,0x01,0x00,0x07,0x07,0x00));	//Restarting the server: Write 0x5001, 07, 0 (false)
				//Process the function result
				else //if(respToF == 0x01)	//Read
					for(off = 4; off < am.length; ) {
						if((off+3) >= am.length)	{ SYS.messDebug("/DNP3",tr("Not enough of the data in %1, the processing terminated").replace("%1",off.toString())); break; }
						dtObj = am.charCodeAt(off), dtObjV = am.charCodeAt(off+1), dtQf = am.charCodeAt(off+2), off += 3;
						dtRcode = (dtQf&0xF);	//Range code
						pntStart = pntStop = 0;
						if(dtRcode == 0)				//8-bit start and stop
							pntStart = am.charCodeAt(off), pntStop = am.charCodeAt(off+1), off += 2;
						else if(dtRcode == 1)		//16-bit start and stop
							pntStart = am.charCodeAt(off, "UTF-16"), pntStop = am.charCodeAt(off+2, "UTF-16"), off += 4;
						else if(dtRcode == 7)		//8-bit Single Field Quantity
							pntStop = am.charCodeAt(off)-1, off += 1;
						else if(dtRcode == 8)		//16-bit Single Field Quantity
							pntStop = am.charCodeAt(off, "UTF-16")-1, off += 2;
						else { SYS.messWarning("/DNP3",tr("Unsupported data range code %1 in %2, the processing terminated").replace("%1",dtRcode.toString()).replace("%2",off.toString())); break; }
						if(pntStart > pntStop)	{ SYS.messDebug("/DNP3",tr("Wrong points range [%1...%2] in %3, the processing terminated").replace("%1",pntStart.toString()).replace("%2",pntStop.toString()).replace("%3",off.toString())); break; }
						SYS.messDebug("/DNP3","pntStart="+pntStart+"; pntStop="+pntStop+"; off="+off);
						
						if(dtObj == 1) {					//Binary Input
							if(dtObjV == 2) {			//.with status
								if((off+(pntStop-pntStart+1)) > am.length)	{ SYS.messDebug("/DNP3",tr("Not enough of the data in %1, the processing terminated").replace("%1",off.toString())); break; }
								for( ; pntStart <= pntStop; pntStart++, off++)
									inVal("di"+pntStart, ((QLT=am.charCodeAt(off))&0x80)?true:false, QLT);
							} else { SYS.messWarning("/DNP3",tr("Binary Input (1): unsupported variant '%1', the processing terminated").replace("%1",dtObjV.toString())); 	break; }
						}
						else if(dtObj == 2) {			//Binary Input Changed
							if(dtObjV == 1) {			//.with status
								if((off+3*(pntStop-pntStart+1)) > am.length)	{ SYS.messDebug("/DNP3",tr("Not enough of the data in %1, the processing terminated").replace("%1",off.toString())); break; }
								for( ; pntStart <= pntStop; pntStart++, off += 3)
									inVal("di"+am.charCodeAt(off,"UTF-16"), ((QLT=am.charCodeAt(off+2))&0x80)?true:false, QLT);
							} else { SYS.messWarning("/DNP3",tr("Binary Input Changed (2): unsupported variant '%1', the processing terminated").replace("%1",dtObjV.toString())); 	break; }
						}
						else if(dtObj == 3) {			//Double-bit Input
							if(dtObjV == 2) {			//.with status
								if((off+(pntStop-pntStart+1)) > am.length)	{ SYS.messDebug("/DNP3",tr("Not enough of the data in %1, the processing terminated").replace("%1",off.toString())); break; }
								for( ; pntStart <= pntStop; pntStart++, off++)
									inVal("di"+pntStart, (((QLT=am.charCodeAt(off))&0xC0)==0xC0||(QLT&0xC0)==0)?EVAL:(QLT&0x40)?true:false, QLT);
							} else { SYS.messWarning("/DNP3",tr("Double-bit Input (3): unsupported variant '%1', the processing terminated").replace("%1",dtObjV.toString())); 	break; }
						}
						else if(dtObj == 4) {			//Double-bit Input Changed
							if(dtObjV == 1) {			//.with status
								if((off+3*(pntStop-pntStart+1)) > am.length)	{ SYS.messDebug("/DNP3",tr("Not enough of the data in %1, the processing terminated").replace("%1",off.toString())); break; }
								for( ; pntStart <= pntStop; pntStart++, off += 3)
									inVal("di"+am.charCodeAt(off,"UTF-16"), (((QLT=am.charCodeAt(off+2))&0xC0)==0xC0||(QLT&0xC0)==0)?EVAL:(QLT&0x40)?true:false, QLT);
							} else { SYS.messWarning("/DNP3",tr("Double-bit Input Changed (4): unsupported variant '%1', the processing terminated").replace("%1",dtObjV.toString())); 	break; }
						}
						else if(dtObj == 10) {			//Binary Output
							if(dtObjV == 2) {			//.with status
								if((off+(pntStop-pntStart+1)) > am.length)	{ SYS.messDebug("/DNP3",tr("Not enough of the data in %1, the processing terminated").replace("%1",off.toString())); break; }
								for( ; pntStart <= pntStop; pntStart++, off++)
									inVal("do"+pntStart, ((QLT=am.charCodeAt(off))&0x80)?true:false, QLT, true);
							} else { SYS.messWarning("/DNP3",tr("Binary Output (10): unsupported variant '%1', the processing terminated").replace("%1",dtObjV.toString())); 	break; }
						}
						else if(dtObj == 20 || dtObj == 21) {	//Binary Counter and Frozen Binary Counter
							if(dtObjV == 1) {							//.default
								if((off+5*(pntStop-pntStart+1)) > am.length)	{ SYS.messDebug("/DNP3",tr("Not enough of the data in %1, the processing terminated").replace("%1",off.toString())); break; }
								for( ; pntStart <= pntStop; pntStart++, off += 5)
									inVal("cnt"+pntStart, am.charCodeAt(off+1,"UTF-32"), am.charCodeAt(off));
							} else { SYS.messWarning("/DNP3",tr("Binary Counter (20) or Frozen Binary Counter (21): unsupported variant '%1', the processing terminated").replace("%1",dtObjV.toString())); 	break; }
						}
						else if(dtObj == 22 || dtObj == 23) {	//Binary Counter Changed and Frozen Binary Counter Changed
							if(dtObjV == 1) {							//.default
								if((off+7*(pntStop-pntStart+1)) > am.length)	{ SYS.messDebug("/DNP3",tr("Not enough of the data in %1, the processing terminated").replace("%1",off.toString())); break; }
								for( ; pntStart <= pntStop; pntStart++, off += 7)
									inVal("cnt"+am.charCodeAt(off,"UTF-16"), am.charCodeAt(off+3,"UTF-32"), am.charCodeAt(off+2));
							} else { SYS.messWarning("/DNP3",tr("Binary Counter Changed (22) or Frozen Binary Counter Changed (23): unsupported variant '%1', the processing terminated").replace("%1",dtObjV.toString())); 	break; }
						}
						else if(dtObj == 30) {			//Analog Input
							if(dtObjV == 1) {			//.32-bit integer value with flag
								if((off+5*(pntStop-pntStart+1)) > am.length)	{ SYS.messDebug("/DNP3",tr("Not enough of the data in %1, the processing terminated").replace("%1",off.toString())); break; }
								for( ; pntStart <= pntStop; pntStart++, off += 5)
									inVal("ai"+pntStart, am.charCodeAt(off+1,"UTF-32"), am.charCodeAt(off));
							} else if(dtObjV == 5) {	//.32-bit floating point value with flag
								if((off+5*(pntStop-pntStart+1)) > am.length)	{ SYS.messDebug("/DNP3",tr("Not enough of the data in %1, the processing terminated").replace("%1",off.toString())); break; }
								for( ; pntStart <= pntStop; pntStart++, off += 5)
									inVal("ai"+pntStart, Special.FLibSYS.floatMergeWord(am.charCodeAt(off+1,"UTF-16"),am.charCodeAt(off+3,"UTF-16")), am.charCodeAt(off));
							} else { SYS.messWarning("/DNP3",tr("Analog Input (30): unsupported variant '%1', the processing terminated").replace("%1",dtObjV.toString())); 	break; }
						}
						else if(dtObj == 32) {			//Analog Input Changed
							if(dtObjV == 7) {			//.32-bit floating point value with flag and event time
								if((off+13*(pntStop-pntStart+1)) > am.length)	{ SYS.messDebug("/DNP3",tr("Not enough of the data in %1, the processing terminated").replace("%1",off.toString())); break; }
								for( ; pntStart <= pntStop; pntStart++, off += 13)
									inVal("ai"+am.charCodeAt(off,"UTF-16"), Special.FLibSYS.floatMergeWord(am.charCodeAt(off+3,"UTF-16"),am.charCodeAt(off+5,"UTF-16")), am.charCodeAt(off+2));
							} else { SYS.messWarning("/DNP3",tr("Analog Input Changed (32): unsupported variant '%1', the processing terminated").replace("%1",dtObjV.toString())); 	break; }
						}
						else if(dtObj == 40) {			//Analog Output
							if(dtObjV == 1) {			//.32-bit integer value with flag
								if((off+5*(pntStop-pntStart+1)) > am.length)	{ SYS.messDebug("/DNP3",tr("Not enough of the data in %1, the processing terminated").replace("%1",off.toString())); break; }
								for( ; pntStart <= pntStop; pntStart++, off += 5)
									inVal("ao"+pntStart, am.charCodeAt(off+1,"UTF-32"), am.charCodeAt(off), true);
							} else { SYS.messWarning("/DNP3",tr("Analog Output (40): unsupported variant '%1', the processing terminated").replace("%1",dtObjV.toString())); 	break; }
						}
						else if(dtObj == 50) {			//Time and Date
							if(dtObjV == 4) {			//.Indexed absolute time and long interval
								if((off+5*(pntStop-pntStart+1)) > am.length)	{ SYS.messDebug("/DNP3",tr("Not enough of the data in %1, the processing terminated").replace("%1",off.toString())); break; }
								for( ; pntStart <= pntStop; pntStart++, off += 11) ;
									//inVal("ao"+pntStart, am.charCodeAt(off+1,"UTF-32"), am.charCodeAt(off));
							} else { SYS.messWarning("/DNP3",tr("Time and Date (4): unsupported variant '%1', the processing terminated").replace("%1",dtObjV.toString())); 	break; }
						}
						else if(dtObj == 110) {			//Time and Date
							if((off+dtObjV*(pntStop-pntStart+1)) > am.length)	{ SYS.messDebug("/DNP3",tr("Not enough of the data in %1, the processing terminated").replace("%1",off.toString())); break; }
							for( ; pntStart <= pntStop; pntStart++, off += dtObjV) ;
						}
						else { SYS.messWarning("/DNP3",tr("Unsupported data object '%1', the processing terminated").replace("%1",dtObj.toString())); break; }
					}
			}
		}
	}
	return "0"+(t_err.length?":"+t_err:"");
}

if(f_start) {
	itemsSet_ = "";
	items = new Object();
	oAVals = new Object();
	transport_ = "", tr = EVAL;
	tmRetr_ = tmResp_ = tmRetr;
	tmPoolEv_ = 0;
	tmPoolAll_ = tmPoolAll;
	ctx = new Object();

	return;
}
if(f_stop) {
	if(!tr.isEVal()) tr.start(false);
	return;
}

//Items set changing process
if(itemsSet != itemsSet_) {
	for(off = 0; (iIt=itemsSet.parse(0,"\n",off)).length; ) {
		iIt_tp = iIt.parse(0, ":");
		iIt_IOA = iIt.parse(1, ":");
		iIt_flgs = iIt.parse(2, ":");
		iIt_nmBase = iIt.parse(3, ":");
		iIt_sDscr = false;
		if((iIt_EndIOA=iIt_IOA.indexOf("-")) >= 0) {
			iIt_EndIOA = iIt_IOA.slice(iIt_EndIOA+1).toInt(0);
			iIt_IOA = iIt_IOA.slice(0,iIt_EndIOA).toInt(0);
		}
		else { iIt_IOA = iIt_EndIOA = iIt_IOA.toInt(0); iIt_sDscr = iIt_nmBase.length; }
		if(iIt_tp == "ai")			{ iIt_nmBase = iIt_nmBase.length ? iIt_nmBase : "AI"; iIt_vtp = "real,ro"; }
		else if(iIt_tp == "ao")	{ iIt_nmBase = iIt_nmBase.length ? iIt_nmBase : "AO"; iIt_vtp = "real"; }
		else if(iIt_tp == "cnt")	{ iIt_nmBase = iIt_nmBase.length ? iIt_nmBase : "CNTR"; iIt_vtp = "int,ro"; }
		else if(iIt_tp == "di")	{ iIt_nmBase = iIt_nmBase.length ? iIt_nmBase : "DI"; iIt_vtp = "boolean,ro"; }
		else if(iIt_tp == "do")	{ iIt_nmBase = iIt_nmBase.length ? iIt_nmBase : "DO"; iIt_vtp = "boolean"; }
		//else if(iIt_tp == "s")		{ iIt_nmBase = iIt_nmBase.length ? iIt_nmBase : "STR"; iIt_vtp = "string,ro"; }
		else continue;
		while(iIt_IOA <= iIt_EndIOA) {
			aId = iIt_tp+iIt_IOA; aDscr = iIt_nmBase+(iIt_sDscr?"":"["+iIt_IOA+"]"); aWr = (iIt_tp == "ao" || iIt_tp == "do");
			if(items[aId].isEVal()) { items[aId] = itW = new Object(); itW.descr = aDscr; itW.wr = aWr; itW.alarm = 0; }
			if(iIt_flgs.indexOf("a") >= 0) {
				this.attrAdd(aId, aDscr, iIt_vtp);
				if(aWr)	oAVals[aId] = EVAL_INT;
				this[aId].set(EVAL_INT, 0, 0, true);
			}
			iIt_IOA++;
		}
	}
	itemsSet_ = itemsSet;

	tmPoolAll_ = tmPoolAll;	//and reread
}

//Check for the transport change and connect
t_err = "0";
if(tr.isEVal() || transport != transport_) {
	itemsSet_ = "";
	items = new Object();
	oAVals = new Object();
	tr = (tr_=SYS.Transport.nodeAt(transport, ".")) ? tr_ : EVAL;
	transport_ = transport;
	if(!tr.isEVal()) tr.start(false);
	tmRetr_ = tmResp_ = tmRetr;
	tmPoolEv_ = 0;
	tmPoolAll_ = tmPoolAll;
}
if(tr.isEVal())	t_err = "1:"+tr("Output transport '%1' error.").replace("%1",transport);
else if(dest < 0 || dest > 65520)
	t_err = "2:"+tr("Destination address '%1' out of range [0...65520].").replace("%1",dest.toString());
else if(src < 0 || src > 65520)
	t_err = "2:"+tr("Source address '%1' out of range [0...65520].").replace("%1",src.toString());
else if(!tr.start()) {
	if(tmRetr_ >= tmRetr) {
		tr.start(true);
		itemsSet_ = "";
		tmRetr_ = tmResp_ = 0;
		tmPoolEv_ = 0;
		tmPoolAll_ = tmPoolAll;
		ctx = new Object();
	} else tmRetr_ += 1/f_frq;
	if(!tr.start())	t_err = "1:"+tr("Output transport '%1' stoped.").replace("%1",transport);
}
else {
	//Init the context
	if(ctx.in.isEVal()) {
		ctx.in = ctx.out = ctx.inAMess = "";
		ctx.trSeq = ctx.appSeq = 0;
		ctx.firSeq = -1;
		ctx.spontEn = false;		//Spontanous messages disabled
		ctx.readAll = false;		//All values readed, stage
		ctx.reqToResp = "";
	}

	//Send output buffer and read the transport for an input data
	if(ctx.out.length) SYS.messDebug("/DNP3",tr("Good output sequence")+": "+SYS.strDecode(ctx.out,"Bin"," "));
	ctx.in += tr.messIO(ctx.out, -0.001);
	ctx.out = "";

	//Input processing
	t_err = processIn();

	//Response timeout
	if(ctx.reqToResp.length) {
		if(tmResp_ > tmRetr)	tr.start(false);	//No response long time
		tmResp_ += 1/f_frq;
	}
	else {
		//Writing
		// By attributes
		for(iIt in oAVals)
			if((aO=this[iIt]) && !(aOval=aO.get()).isEVal() && aOval != oAVals[iIt]) {
				if(iIt.slice(0,2) == "do")
					mess(0x02, SYS.strFromCharCode(10,2,0,iIt.slice(2).toInt(),iIt.slice(2).toInt(),aOval?1:0));
				else if(iIt.slice(0,2) == "ao")
					mess(0x02, SYS.strFromCharCode(40,1,0,iIt.slice(2).toInt(),iIt.slice(2).toInt(),0)+SYS.strFromCharUTF("UTF-32",aOval));
				oAVals[iIt] = aOval;
			}
		// By items object
		for(iIt in items)
			if((aO=items[iIt]) && !(aOval=aO.set).isEVal()) {
				if(iIt.slice(0,2) == "do")
					mess(0x02, SYS.strFromCharCode(10,2,0,iIt.slice(2).toInt(),iIt.slice(2).toInt(),aOval?1:0));
				else if(iIt.slice(0,2) == "ao")
					mess(0x02, SYS.strFromCharCode(40,1,0,iIt.slice(2).toInt(),iIt.slice(2).toInt(),0)+SYS.strFromCharUTF("UTF-32",aOval));
				aO.set = EVAL_BOOL;
			}

		//Polling
		// Read all classes
		if(tmPoolAll_ > tmPoolAll)		{ mess(0x1, SYS.strFromCharCode(0x3C,0x02,0x06,0x3C,0x03,0x06,0x3C,0x04,0x06,0x3C,0x01,0x06));	tmPoolAll_ = 0; ctx.readAll = true; }
		//Read periodically the class 1
		else if(tmPoolEv_ > tmPoolEv) {
			// Enable the spontanous messages
			if(!ctx.spontEn)	{ mess(0x14, SYS.strFromCharCode(0x3C,0x02,0x06,0x3C,0x03,0x06,0x3C,0x04,0x06)); ctx.spontEn = true; }
			else mess(0x1, SYS.strFromCharCode(0x3C,0x02,0x06));
			tmPoolEv_ = 0;
		}

		if(ctx.readAll)	tmPoolEv_ += 1/f_frq;
		tmPoolAll_ += 1/f_frq;
		tmResp_ = 0;
	}
}

//Error set
if(t_err.toInt()) {
	if(!tr.isEVal() && tr.start()) tr.start(false);
	if(f_err != t_err) {
		items = new Object();
		oAVals = new Object();
		aLs = this.nodeList("a_");
		for(iA = 0; iA < aLs.length; iA++)
			if((aPref=aLs[iA].slice(2,4)) == "di" || aPref == "do" || aPref == "ai" || aPref == "ao")
				this[aLs[iA].slice(2)].set(EVAL_INT, 0, 0, true);
		SYS.messDebug("/DNP3", tr("Error")+": "+t_err);
	}
}
f_err = t_err;


ID: IEC62056
NAME: IEC-62056
uk#NAME: IEC-62056
DESCR:
IEC 62056 part 46 is one from the IEC 62056 set of standards which defines systems used for telecontrol (supervisory control and data acquisition) in electrical engineering and power system automation applications. Part 46 defines Data link layer using HDLC protocol, which uses mostly on serial interfaces.

Author: Roman Savochenko <roman@oscada.org>
State of the protocol implementing: Client of the specification part 46, reading of the directly specified OBIS
Total complexity: 3.2 HD
Sponsored by: SVItoVYR Ltd for whole complexity
Version: 1.1.2
License: GPLv2

uk#DESCR:
IEC 62056 у частині 46 є одним з набору стандартів IEC 62056 який визначає системи, що використовуються у віддаленому контролі (телемеханіці — диспетчерському контролі та зборі даних) у інженерній електриці та у застосунках автоматизації енергетичних систем. Частина 46 надає шар підключення Даних з використанням протоколу HDLC, який переважно використовується на послідовних інтерфейсах.

Автор: Роман Савоченко <roman@oscada.org>
Стан реалізації протоколу: Клієнт частини 46 специфікації, читання прямо визначених OBIS
Загальна працемісткість: 3.2 ЛД
Спонсорування: ТОВ "СВІТоВИР АВТоМАТИК" на загальну працемісткість
Версія: 1.1.2
Ліцензія: GPLv2

PROGRAM:
JavaLikeCalc.JavaScript
function CRC( inSeq ) { return Special.FLibSYS.CRC(inSeq, 16, 0x1021, -1, true, true, 0xFFFF); }

function ASN1_Data( inSeq, offIn ) {
	val = EVAL;
	offIn += 1;
	if((vTp=inSeq.charCodeAt(offIn-1)) == 0)	//NULL
		val = 0;
	else if(vTp == 1 || vTp == 2) {		//Array, Structure
		itSz = inSeq.charCodeAt(offIn);
		val = new Array(itSz);
		offIn += 1;
		for(itI = 0; itI < itSz; itI++)
			val[itI] = ASN1_Data(inSeq, offIn);
	}
	else if(vTp == 4 || vTp == 18) {		//BIT STRING, Unsigned16
		val = inSeq.charCodeAt(offIn, "UTF-16BE");
		offIn += 2;
	}
	else if(vTp == 5) {							//Integer32
		val = inSeq.charCodeAt(offIn, "UTF-32BE");
		if(val > 2147483647) val -= 4294967296;
		offIn += 4;
	}
	else if(vTp == 6) {							//Unsigned32
		val = inSeq.charCodeAt(offIn, "UTF-32BE");
		offIn += 4;
	}
	else if(vTp == 9 || vTp == 10) {		//OCTET STRING, VisibleString
		itSz = inSeq.charCodeAt(offIn);
		val = inSeq.slice(offIn+1, offIn+1+itSz);
		offIn += 1+itSz;
	}
	else if(vTp == 13 || vTp == 15) {		//Integer8
		val = inSeq.charCodeAt(offIn);
		if(val > 127) val -= 256;
		offIn += 1;
	}
	else if(vTp == 16) {						//Integer16
		val = inSeq.charCodeAt(offIn, "UTF-16BE");
		if(val > 32767) val -= 65536;
		offIn += 2;
	}
	else if(vTp == 17 || vTp == 22) {		//Unsigned8, ENUMERATED
		val = inSeq.charCodeAt(offIn);
		offIn += 1;
	}
	else if(vTp == 18) {						//Unsigned16
		val = inSeq.charCodeAt(offIn, "UTF-16BE");
		offIn += 2;
	}
	else {
		SYS.messDebug("/IEC62056", tr("Unknown data type %1, termination").replace("%1",vTp.toString()));
		offIn = inSeq.length;
	}

	return val;
}

function inVal( aId, aVal ) {
	aId_ = aId.replace(".", "_"); 
	if(items[aId_].isEVal()) {
		items[aId_] = itW = new Object();
		itW.descr = aId;
		itW.wr = false; itW.alarm = 0;
	} else itW = items[aId_];
	itW.val = aVal;
	if((aO=this[aId_]).isEVal()) {
		if((aTp=typeof(aVal)) == "array")	aTp = "object";
		else if(aTp == "real") ;
		else if(aTp == "int")	aTp = "integer";
		else aTp = "string";
		this.attrAdd(aId_, aId, aTp+",ro");
		aO = this[aId_];
	}
	aO.set(aVal, 0, 0, true);
}

function processIn( isSync ) {
	t_err = "";
	//Parse for packages in general - the transport layer
	for(waitSz = 0; ctx.in.length; ctx.in = ctx.in.slice(waitSz)) {
		// Checking for very short
		if(ctx.in.length < 9)	{ if(isSync == true) return "10:"+tr("Too short"); break; }
		// Checking the header entirety
		if(ctx.in[0] != "~" || ((form=ctx.in.charCodeAt(1))&0xF0) != 0xA0 || ((dataSz=ctx.in.charCodeAt(1,"UTF-16BE")&0x07FF) < 7) ||
				//  Checking the source address
				!((src_=ctx.in.charCodeAt(3))&1) || (src_>>1) != src) {
			SYS.messDebug("/IEC62056",tr("Wrong header or source address, rejected")+": "+SYS.strDecode(ctx.in,"Bin"," "));
			if(isSync == true) return "11:"+tr("Wrong header or source address, rejected");
			ctx.in = "";
			break;
		}
		//  Checking the destination address
		if(((dst_=ctx.in.charCodeAt(4))&1) && (dst_>>1) == ctx.destUp && ctx.destLow == 0)
			dst_sz = 1;
		else if(!((dst_=ctx.in.charCodeAt(4))&1) && ((dst_2=ctx.in.charCodeAt(5))&1) && (dst_>>1) == ctx.destUp && (dst_2>>1) == ctx.destLow)
			dst_sz = 2;
		else if(!((dst_=ctx.in.charCodeAt(4))&1) && !(ctx.in.charCodeAt(5)&1) && !((dst_2=ctx.in.charCodeAt(6))&1) && (ctx.in.charCodeAt(7)&1) &&
				(((dst_>>1)<<7)|(ctx.in.charCodeAt(5)>>1)) == ctx.destUp && (((dst_2>>1)<<7)|(ctx.in.charCodeAt(7)>>1)) == ctx.destLow)
			dst_sz = 4;
		else {
			SYS.messDebug("/IEC62056",tr("Wrong destination address, rejected")+": "+SYS.strDecode(ctx.in,"Bin"," "));
			if(isSync == true) return "11:"+tr("Wrong destination address, rejected");
			ctx.in = "";
			break;
		}
		// Short yet, waiting
		if(ctx.in.length < (7+dst_sz))	{ if(isSync == true) return "10:"+tr("Too short"); break; }
		//  Checking the header CRC
		if(CRC(ctx.in.slice(1,5+dst_sz)) != ctx.in.charCodeAt(5+dst_sz,"UTF-16LE")) {
			SYS.messDebug("/IEC62056",tr("CRC-error, rejected")+": "+SYS.strDecode(ctx.in,"Bin"," "));
			if(isSync == true) return "11:"+tr("CRC-error, rejected");
			ctx.in = "";
			break;
		}
		// Checking the frame entirety
		//  Not full yet, waiting
		if(ctx.in.length < (waitSz=2+dataSz)) { if(isSync == true) return "10:"+tr("Too short"); break; }
		if(ctx.in[waitSz-1] != "~") {
			SYS.messDebug("/IEC62056",tr("The end symbol is wrong")+": "+SYS.strDecode(ctx.in,"Bin"," "));
			if(isSync == true) return "11:"+tr("The end symbol is wrong");
			ctx.in = "";
			break;
		}
		//  Checking the frame CRC with the data
		if(dataSz > (6+dst_sz) && CRC(ctx.in.slice(1,1+dataSz-2)) != ctx.in.charCodeAt(1+dataSz-2,"UTF-16LE")) {
			SYS.messDebug("/IEC62056",tr("CRC-error, rejected")+": "+SYS.strDecode(ctx.in,"Bin"," "));
			if(isSync == true) return "11:"+tr("CRC-error, rejected");
			ctx.in = "";
			break;
		}

		SYS.messDebug("/IEC62056",tr("Good input sequence")+": "+SYS.strDecode(ctx.in.slice(0,waitSz),"Bin"," "));

		cntr = ctx.in.charCodeAt(4+dst_sz);
		// Checking the control byte, sequinces and the frame segments
		if((cntr&0x7) == 1) {	//RR
			SYS.messDebug("/IEC62056", "RR"+(cntr>>5)+((cntr&0x10)?"F":""));
			if(ctx.reqToResp == "RR")	ctx.reqToResp = "";
			continue;
		}
		else if(!(cntr&1)) {	//I
			SYS.messDebug("/IEC62056", "I"+((cntr>>1)&0x7)+","+(cntr>>5)+((cntr&0x10)?"F":""));
			if(ctx.sendSeq != (cntr>>5)) {
				SYS.messDebug("/IEC62056", tr("Broken sequence %1, rejected").replace("%1",ctx.sendSeq.toString()));
				continue;
			}
			if(ctx.readSeq >= 7) ctx.readSeq = 0; else ctx.readSeq++;
			if(cntr&0x10)	ctx.sendRR = true; //mess("RR");		//F - final
		}

		ctx.inAMess += ctx.in.slice(7+dst_sz, 1+dataSz-2);
		if(form&0x8)	continue;	//Waiting the next segment

		// Getting the data
		if(cntr == 0x73)	{	//UA
			SYS.messDebug("/IEC62056", "UA");
			if(ctx.toInit == 1 && ctx.reqToResp == "SNRM")	{
				ctx.toInit++;
				//!!!! Parsing the SNRM result
			}
			ctx.reqToResp = "";
		}
		else if((cntr&0x11) == 0x10) {	//I,F
			if(ctx.inAMess.slice(0,4) == SYS.strFromCharCode(0xE6,0xE7,0x00,0x61)) {	//LPDU, APPLICATION 1, Initial parameter acquiring
				if(ctx.inAMess.indexOf(SYS.strFromCharCode(0xA2,0x03,0x02,0x01,0x00)) >= 0) ctx.toInit++;
				else { t_err += tr("Error the authentication")+"; "; tr.start(false); }
				//!!!! Deep parsing the initial parameter acquiring
			}
			else if(ctx.inAMess.slice(0,5) == SYS.strFromCharCode(0xE6,0xE7,0x00,0xC4,0x01)) {	//LPDU, GET-Response-Normal
				tVl = ctx.inAMess.charCodeAt(5);		//Invoke-Id-And-Priority
				// Get-Data-Result
				if((tVl=ctx.inAMess.charCodeAt(6)) == 0) {	// Data
					val = ASN1_Data(ctx.inAMess, 7);
					//Processing the result
					// Array of the variables with OBIS and values
					if(typeof(val) == "array" && val.length == 1 && typeof(val[0]) == "array" && val[0].length && typeof(val[0][0]) == "array" && val[0][0].length == 3)
						for(iIt = 0; iIt < val[0].length; iIt++) {
							wIt = val[0][iIt];
							tVl = val[0][iIt][0];
							for(iIt_OBIS = "", iN = 0; iN < tVl.length; iN++)
								iIt_OBIS += (iIt_OBIS.length?".":"") + tVl.charCodeAt(iN).toString();
							inVal(iIt_OBIS, val[0][iIt][1]*pow(10,val[0][iIt][2][0]));
						}
					// Single variable
					else inVal(ctx.reqOBIS, val);
					SYS.messDebug("/IEC62056", "Data value: "+typeof(val));
				}
				else if(tVl == 1)										// Error
					t_err += tr("Error the data %1").replace("%1",ctx.inAMess.charCodeAt(7).toString())+"; ";
			}
		}
		ctx.inAMess = "";
	}
	return "0"+(t_err.length?":"+t_err:"");
}

//Forming of the message and placing it to the output buffer
//  Commands: "SNRM", "RR", "I", "DISC"
function mess( com, data ) {
	if(data.isEVal())	data = "";
	mLen = 10 + (data.length ? data.length+2 : 0);
	 //SYS.strFromCharCode(ac, func) + objs;
	aMess = SYS.strFromCharCode(0xA0|(mLen>>8), mLen&0xFF);
	if(!ctx.destLow && ctx.destUp < 128)					aMess += SYS.strFromCharCode(((ctx.destUp&0x7F)<<1)|1);
	else if(ctx.destUp < 128 && ctx.destLow < 128)	aMess += SYS.strFromCharCode((ctx.destUp&0x7F)<<1, ((ctx.destLow&0x7F)<<1)|1);
	else aMess += SYS.strFromCharCode((ctx.destUp>>7)<<1, (ctx.destUp&0x7F)<<1, (ctx.destLow>>7)<<1, ((ctx.destLow&0x7F)<<1)|1);
	aMess += SYS.strFromCharCode((src<<1)|1);
	ctx.reqToResp = com;
	if(com == "SNRM")		aMess += SYS.strFromCharCode(0x93);
	else if(com == "RR")	aMess += SYS.strFromCharCode((ctx.readSeq<<5)|0x11);
	else if(com == "DISC")	aMess += SYS.strFromCharCode(0x53);
	else if(com == "I") {
		aMess += SYS.strFromCharCode(0x10|(ctx.readSeq<<5)|(ctx.sendSeq<<1));
		if(ctx.sendSeq >= 7) ctx.sendSeq = 0; else ctx.sendSeq++;
	} else return;	
	aMess += SYS.strFromCharUTF("UTF-16LE",CRC(aMess)) + data;
	if(data.length)	aMess += SYS.strFromCharUTF("UTF-16LE",CRC(aMess));
	aMess = SYS.strFromCharCode(0x7E) + aMess + SYS.strFromCharCode(0x7E);
	ctx.out += aMess;
	//Just direct writing per one message
	//SYS.messDebug("/IEC62056",tr("Good output sequence")+": "+SYS.strDecode(aMess,"Bin"," "));
	//tr.messIO(aMess, 0, 0);

	//Synchronous request-response
	SYS.messDebug("/IEC62056",tr("Good output sequence")+": "+SYS.strDecode(ctx.out,"Bin"," "));
	t_err = "0";
	ctx.in = tr.messIO(ctx.out); ctx.out = "";
	if(!ctx.in.length)	{ t_err = "10:"+tr("No response"); tr.start(false); }
	else while((t_err=processIn(true)).toInt() == 10 && (respTail=tr.messIO("")).length) ctx.in += respTail;

	return t_err;
}

if(f_start) {
	itemsSet_ = "";
	items = new Object();
	//oAVals = new Object();
	transport_ = "", tr = EVAL;
	tmRetr_ = tmResp_ = tmRetr;
	tmPollAll_ = tmPollAll; offPoll = 0;
	ctx = new Object();

	return;
}

t_err = "0";

if(f_stop)	t_err = mess("DISC");

//Items set changing process
if(itemsSet != itemsSet_) {
	itemsSet_ = itemsSet;
	tmPollAll_ = tmPollAll; offPoll = 0;		//and reread
}

//Check for the transport change and connect
destUp = dest.parse(0,":").toInt(); destLow = dest.parse(1,":").toInt();
if(tr.isEVal() || transport != transport_)	{
	itemsSet_ = "";
	items = new Object();
	//oAVals = new Object();
	tr = SYS.Transport.nodeAt(transport, ".");
	transport_ = transport;
	if(!tr.isEVal()) tr.start(false);
	tmRetr_ = tmResp_ = tmRetr;
	tmPollAll_ = tmPollAll; offPoll = 0;
}
if(tr.isEVal())	t_err = "1:"+tr("Output transport '%1' error.").replace("%1",transport);
else if(destUp < 0 || destUp > 16383)
	t_err = "2:"+tr("Upper HDLC destination address '%1' out of range [0...16383].").replace("%1",destUp.toString());
else if(destLow < 0 || destLow > 16383)
	t_err = "2:"+tr("Lower HDLC destination address '%1' out of range [0...16383].").replace("%1",destUp.toString());
else if(src < 0 || src > 127)
	t_err = "2:"+tr("Source address '%1' out of range [0...127].").replace("%1",src.toString());
else if(!tr.start()) {
	if(tmRetr_ >= tmRetr) {
		tr.start(true);
		itemsSet_ = "";
		tmRetr_ = tmResp_ = 0;
		tmPollAll_ = tmPollAll; offPoll = 0;
		ctx = new Object();
		ctx.destUp = destUp; ctx.destLow = destLow;
		pass_ = pass;
	} else tmRetr_ += 1/f_frq;
	if(!tr.start())	t_err = "1:"+tr("Output transport '%1' stoped.").replace("%1",transport);
}
else if(ctx.destUp != destUp || ctx.destLow != destLow || pass != pass_)	tr.start(false);
else {
	//Init the context
	if(ctx.in.isEVal()) {
		ctx.in = ctx.out = ctx.inAMess = "";
		ctx.sendSeq = ctx.readSeq = 0;
		ctx.toInit = 1;
		ctx.firSeq = -1;
		ctx.sendRR = false;
		ctx.reqToResp = "";
	}

	//Send output buffer and read the transport for an input data
	// Asynchronous mode
	//if(ctx.out.length) SYS.messDebug("/IEC62056",tr("Good output sequence")+": "+SYS.strDecode(ctx.out,"Bin"," "));
	//ctx.in += tr.messIO(ctx.out, -0.001);
	//ctx.out = "";

	//Input processing
	//t_err = processIn();

	//Response timeout
	/*if(ctx.reqToResp.length) {
		if(tmResp_ > tmRetr)	tr.start(false);	//No response long time
		tmResp_ += 1/f_frq;
	}
	// Initial parameters setting
	else*/
	if(!t_err.toInt() && ctx.toInit == 1)
		t_err = mess("SNRM", SYS.strFromCharCode(
			0x81,0x80,0x12,		//format and group identifier, length 18 bytes
				0x05,0x01,0x80,	//the parameter "Maximum information field length - transmit" = 128
				0x06,0x01,0x80,	//the parameter "Maximum information field length - receive" = 128
				0x07,0x04,0x00,0x00,0x00,0x01,	//the parameter "Window size - transmit" = 1
				0x08,0x04,0x00,0x00,0x00,0x07	//the parameter "Window size - receive" = 7
			));
	// Initial parameter acquiring
	if(!t_err.toInt() && ctx.toInit == 2)
		t_err = mess("I", SYS.strFromCharCode(
			0xE6,								//Destination (remote) LSAP, fixed in COSEM
			0xE6,								//Source (local) LSAP, fixed in COSEM E6 for command E7 for response
			0x00,								//Quality, Control byte, Reserved and 00 always
			0x60, 46+pass.length,		//APPLICATION 0, Length 54
			0xA1, 0x09, 0x06, 0x07,	//Application-context-name [1] (9 byte), OBJECT IDENTIFIER (7 byte)
				0x60, 0x85, 0x74, 0x05, 0x08, 0x01, 0x01,
			0x8A, 0x02, 0x07, 0x80,	//ACSE-requirements [10], BIT STRING (7) = 0x80
			0x8B, 0x07,						//Security Mechanism-name [11]
				0x60, 0x85, 0x74, 0x05, 0x08, 0x02, 0x01,
			0xAC, pass.length+2, 0x80, pass.length) + //Authentication-value [12], GraphicString (0x80), Key value
				pass + SYS.strFromCharCode(
			0xBE, 0x10, 0x04, 0x0E,	//Association-information [30], Client information, OCTET STRING (4)
				0x01,							// Data tag for the request
				0x00, 0x00, 0x00,		// Flags field
				0x06, 0x5F, 0x1F,		// Application tag, 31
				0x04, 0x00, 0x00, 0x18, 0x1D,	// Client side services
				0x00, 0x00					// PDU maximum size
			));
	if(!t_err.toInt() && ctx.toInit > 2) {
		if(ctx.sendRR)	{ t_err = mess("RR"); ctx.sendRR = false; }
		//Polling
		// Read all items
		if(!t_err.toInt() && tmPollAll_ > tmPollAll) {
			if((iIt=itemsSet.parse(0,"\n",offPoll)).length) {
				iIt_ClassId = iIt.parse(0, "-");
				iIt_OBIS = iIt.parse(1, "-");
				iIt_a = iIt.parse(2, "-");
				ctx.reqOBIS = iIt_OBIS;
				t_err = mess("I", SYS.strFromCharCode(0xE6, 0xE6, 0x00,
					0xC0, 0x01, 0x81,	//Get-Request-Normal, Invoke-Id-And-Priority
					0x00, iIt_ClassId.toInt(),	//Cosem-Class-Id, ?
					iIt_OBIS.parse(0,".").toInt(), iIt_OBIS.parse(1,".").toInt(), iIt_OBIS.parse(2,".").toInt(), iIt_OBIS.parse(3,".").toInt(), iIt_OBIS.parse(4,".").toInt(), iIt_OBIS.parse(5,".").toInt(),
					iIt_a.toInt(),		//Cosem-Object-Attribute-Id
					0x00						//Selective-Access-Descriptor, 0
				));
			}
			if(offPoll >= itemsSet.length) { tmPollAll_ = 0; offPoll = 0; }
		}

		tmPollAll_ += 1/f_frq;
		tmResp_ = 0;
	}
}

//Error set
if(t_err.toInt()) {
	if(!tr.isEVal() && tr.start()) tr.start(false);
	if(f_err != t_err) {
		for(var iIt in items)
			this[iIt].set(EVAL_REAL, 0, 0, true);
		items = new Object();
		SYS.messDebug("/IEC62056", tr("Error")+": "+t_err);
	}
}
f_err = t_err;

if(f_stop && !tr.isEVal()) tr.start(false);


ID: MTP4D
NAME: MTP 4D
uk#NAME: MTP 4D
DESCR:
The connection template of a simple vaccuumeter MTP 4D of the firm "Erstevak Ltd (http://www.erstvak.com/)".

Author: Roman Savochenko <roman@oscada.org>
Total complexity: 0.3 HD
Sponsored by, for whole complexity: Magomed, SAVTECH
Version: 1.1.0
License: GPLv2

PROGRAM:
JavaLikeCalc.JavaScript
//Same request to the device
function req(data) {
	data = addr.toString(10,3) + data;

	//CRC calculation
	for(CRC = 0, iS = 0; iS < data.length; iS++) CRC += data.charCodeAt(iS);
	data += SYS.strFromCharCode((CRC%64)+64, 0x0D);

	for(resp = tr.messIO(data); resp[resp.length-1] != "\r" && (respTail=tr.messIO("")).length; )
		resp += respTail;

	if(resp.length < 6 || resp[resp.length-1] != "\r" || resp.slice(0,4) != data.slice(0,4))
		return "10:"+tr("Wrong or no response.");
	resp = resp.slice(0,-1);
	for(CRC = 0, iS = 0; iS < resp.length-1; iS++) CRC += resp.charCodeAt(iS);
	if(((CRC%64)+64) != resp.charCodeAt(resp.length-1))
		return "11:"+tr("Error CRC.");

	data = resp.slice(3,-1);

	return "0";
}

if(f_start) {
	f_err = "0";
	transport_ = transport;
	type = P = EVAL;
	zeroP = zeroAP = false;
	tr = EVAL;
}

if(f_start || f_stop) return;

t_err = "";

//Check for the transport change and connect
if(tr.isEVal() || transport != transport_)	{
	tr = SYS.Transport[transport.parse(0)]["out_"+transport.parse(1)];
	transport_ = transport;
}
if(tr.isEVal())	t_err = "1:"+tr("Output transport '%1' error.").replace("%1",transport);
else if(addr < 1 || addr > 999)
	t_err = "2:"+tr("Address '%1' out of range [1...999].").replace("%1",addr.toString());
else {
	//Setting
	if(zeroAP && !t_err.toInt()) {
		data = "j1";
		if(!(t_err=req(data)).toInt()) {
			data = "j100023";
			if(!(t_err=req(data)).toInt())	zeroAP = false;
		}
	}
	if(zeroP && !t_err.toInt()) {
		data = "j0";
		if(!(t_err=req(data)).toInt()) {
			data = "j000000";
			if(!(t_err=req(data)).toInt())	zeroP = false;
		}
	}

	//Reading
	data = "T";
	if(!t_err.toInt() && !(t_err=req(data)).toInt())	type = data.slice(1);
	else type = EVAL;

	data = "M";
	if(!t_err.toInt() && !(t_err=req(data)).toInt())
		P = data.slice(1,5).toReal()*1e-3*pow(10,data.slice(5,7).toReal()-20);
	else P = EVAL;
}

if(t_err.toInt()) { f_err = t_err; type = P = EVAL; }
else f_err = "0";


ID: mbBase
NAME: ModBus base
DESCR:
ModBus base template of the protocol implementing on the Logical Level. Designed mostly to use in the base of creation specific ModBus-based protocols for the standard-part registers' access (function 3 for reading and function 16 for writing) and appending the new protocol specific part. The template was designed to work both under control of the controller objects of the module ModBus and LogicLev and can be managed from the template of the initiative connections processing for assigned output transports.

Author: Roman Savochenko <roman@oscada.org>
Total complexity: 0.5 HD
Sponsored by, for whole complexity: Elyor Turaboev, BLUE STAR GROUP Ltd
Version: 1.0.0
License: GPLv2

PROGRAM:
JavaLikeCalc.JavaScript
//Same request to the device
function req(PDU) {
	// For placing into the module ModBus
	if(!transport.length)	return this.cntr().messIO(PDU);

	// For other logical level
	reqO = SYS.XMLNode(mbType).setAttr("id","Goboy").setAttr("node",addr).setText(PDU);
	if((rez=tr.messIO(reqO,"ModBus")).length)	return "10:"+rez;
	PDU = reqO.text();

	return reqO.attr("err");
}

if(f_start) {
	transport_ = transport;
	tr = EVAL;
	dt = new Object();
	items_ = "";
}

//Parse the items set and create user attributes
if(items != items_) {
	items_ = items;
	// Mark for check to deletion needs
	for(var iDt in dt)
		if(iDt != "10000") dt[iDt].mark = false;
	// Append/Update present ones
	for(off = 0; (sIt=items.parseLine(0,off)).length; ) {
		if(sIt[0] == "#")	continue;
		off1 = 0;
		itO = new Object();
		itO.tp = sIt.parse(0, ":", off1);
		tmpAddr = sIt.parse(0, ":", off1);
		itO.addr = tmpAddr.toInt();
		itO.md = sIt.parse(0, ":", off1);
		itO.id = sIt.parse(0, ":", off1);
		itO.nm = sIt.slice(off1);
		dt[itO.addr.toString(16,5)] = itO;
		if(itO.tp == "u" || itO.tp == "i" || itO.tp == "u2" || itO.tp == "i2")	{ wTp = "integer"; itO.sz = 2; }
		else if(itO.tp == "u4" || itO.tp == "i4")	{ wTp = "integer"; itO.sz = 4; }
		else if(itO.tp == "s")	{ wTp = "string"; itO.sz = 16; }
		else { wTp = "real"; itO.sz = 4; }
		itO.rd = (itO.md.indexOf("r") >= 0);
		itO.wr = (itO.md.indexOf("w") >= 0);
		itO.rev = (itO.md.indexOf("~") >= 0);
		if(!itO.wr)	wTp += "|ro";
		if(itO.rd || itO.wr) {
			this.attrAdd(itO.id, itO.nm, wTp);
			if(itO.wr)	itO.val = this[itO.id].get();
			itO.mark = true;
			//SYS.messInfo("/ED","itO="+itO.id+"; tmpAddr="+tmpAddr+"; addr="+itO.addr);
		}
	}
	dt["10000"] = EVAL;
	// Check, remove item and set to EVAL the attribute
	for(var iDt in dt) {
		if(iDt == "10000" || dt[iDt].mark)	continue;
		this[dt[iDt].id].set(EVAL, 0, 0, true);
		delete dt[iDt];
	}
}

if(f_start || f_stop) return;

tErr = "";

//Checking for the transport change and connect
if(tr.isEVal() || transport != transport_)	{
	if(!transport.length) {
		if(!((tVl=this.cntr().cfg("PROT")) == "RTU" || tVl == "ASCII" || tVl == "TCP")) {
			tr = EVAL;
			tErr = "1:"+tr("Output transport is empty and the controller object is not ModBus.");
		}
		else {
			tr = new Object();
			maxBlkSz = this.cntr().cfg("MAX_BLKSZ");
			if(maxBlkSz.isEVal())	maxBlkSz = 12;
			fragMerge = this.cntr().cfg("FRAG_MERGE");
			if(fragMerge.isEVal())	fragMerge = false;
		}
	} else tr = SYS.Transport[transport.parse(0)]["out_"+transport.parse(1)];
	maxBlkSz = max(10, min(200,maxBlkSz));
	transport_ = transport;
}
if(tErr.toInt()) ;
else if(tr.isEVal())
	tErr = "1:"+tr("Output transport '%1' error.").replace("%1",transport);
else if(addr < 0 || addr > 247)
	tErr = "2:"+tr("Address '%1' out of range [0...247].").replace("%1",addr.toString());
else {
	//Check for changed attributes and perform writing
	for(var iDt in dt) {
		isEOL = (iDt == "10000");
		itO = dt[iDt];
		tVl = this[itO.id].get();
		if(isEOL || !itO.wr || tVl.isEVal() || itO.val == tVl)	continue;
		PDU = Special.FLibSYS.IO("", "", "b");
		PDU.wr(16,"uint8").wr(itO.addr,"uint16").wr(floor(itO.sz/2),"uint16").wr(itO.sz,"uint8");
		if(itO.tp == "u" || itO.tp == "u2")			PDU.wr(tVl,"uint16");
		else if(itO.tp == "i" || itO.tp == "i2")	PDU.wr(tVl,"int16");
		else if(itO.tp == "u4")	{
			if(itO.rev)	PDU.wr(tVl>>16, "uint16").wr(tVl&0xFFFF, "uint16");
			else	PDU.wr(tVl&0xFFFF, "uint16").wr(tVl>>16, "uint16");
		}
		else if(itO.tp == "i4") {
			if(itO.rev)	PDU.wr(tVl>>16, "int16").wr(tVl&0xFFFF, "uint16");
			else	PDU.wr(tVl&0xFFFF, "uint16").wr(tVl>>16, "int16");
		}
		else if(itO.tp == "s")		PDU.wr(tVl.slice(0,16),"char").wr(" ","char",16-min(16,tVl.length));
		else {
			w1 = w2 = 0;
			if(itO.rev)	Special.FLibSYS.floatSplitWord(tVl, w2, w1);
			else	Special.FLibSYS.floatSplitWord(tVl, w1, w2);
			PDU.wr(w1, "uint16").wr(w2, "uint16");
		}
		//SYS.messInfo("/ED","reqPDU="+SYS.strDecode(PDU.string,"Bin"," "));
		if(!req(PDU.string).toInt())	itO.val = tVl;
		//SYS.messInfo("/ED","respPDU="+SYS.strDecode(PDU.string,"Bin"," "));
	}

	//Same requests for the data
	blk = new Array();
	for(var iDt in dt) {
		isEOL = (iDt == "10000");
		itO = dt[iDt];
		//SYS.messInfo("/ED","iDt="+iDt+"; isEOL="+isEOL);
		if(!isEOL && (!blk.length || (
				(itO.addr-blk[0].addr+1+floor((itO.sz-2)/2)) <= floor(maxBlkSz/2) && (fragMerge || (itO.addr-blk[blk.length-1].addr-floor((blk[blk.length-1].sz-2)/2)) <= 1) ))) {
			if(itO.rd) blk.push(itO);
			continue;
		}
		//Send request for this block
		if(blk.length) {
			regN = (blk[blk.length-1].addr - blk[0].addr) + 1 + floor((blk[blk.length-1].sz-2)/2);
			PDU = SYS.strFromCharCode(3, (blk[0].addr>>8)&0xFF, blk[0].addr&0xFF, 0, regN);
			//SYS.messInfo("/ED","reqPDU="+SYS.strDecode(PDU,"Bin"," "));
			if((tErr=req(PDU)).toInt()) break;
			//SYS.messInfo("/ED","respPDU="+SYS.strDecode(PDU,"Bin"," "));
			io = Special.FLibSYS.IO(PDU, "", "b");
			rF = io.read("uint8", 1); rN = io.read("uint8", 1);
			if(rF != 3 || (io.length-2) != rN) { tErr = "10:"+tr("Inconsistent respond's length."); break; }
			for(iB = 0; iB < blk.length; iB++) {
				itO1 = blk[iB];
				io.pos = 2 + (itO1.addr-blk[0].addr)*2;
				if(itO1.tp == "u" || itO1.tp == "u2")			tVl = io.read("uint16", 1);
				else if(itO1.tp == "i" || itO1.tp == "i2")	tVl = io.read("int16", 1);
				else if(itO1.tp == "u4")
					tVl = itO1.rev ? io.read("uint16", 1)*65536 + io.read("uint16", 1) :
											io.read("uint16", 1) + io.read("uint16", 1)*65536;
				else if(itO1.tp == "i4")
					tVl = itO1.rev ? io.read("int16", 1)*65536 + io.read("uint16", 1) :
											io.read("uint16", 1) + io.read("int16", 1)*65536;
				else if(itO1.tp == "s")	tVl = io.read("char", blk[0].sz);
				else {
					w1 = io.read("uint16", 1); w2 = io.read("uint16", 1);
					tVl = itO1.rev ? Special.FLibSYS.floatMergeWord(w2, w1) :
											Special.FLibSYS.floatMergeWord(w1, w2);
					//tVl = io.read("float", 1, "l");
				}
				if(itO1.wr && itO1.val != this[itO1.id].get())	{ itO1.val = tVl; continue; }
				this[itO1.id].set(tVl, 0, 0, true);
				itO1.val = tVl;
			}
			blk = new Array(); blk.push(itO);
		}
	}
}

if(!tErr.length)	tErr = "0";
if(tErr.toInt()) {
	if(!tr.isEVal() && tr.start()) tr.start(false);
	if(f_err != tErr)
		for(var iDt in dt) {
			itO = dt[iDt];
			if(iDt == "10000")	continue;
			this[itO.id].set(EVAL, 0, 0, true);
		}
}
f_err = tErr;


