# 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:
  The library was created to provide main templates of the DAQ-sources processing and related services.

  Author: Roman Savochenko <roman@oscada.org>
  Founded: 2006
  Version: 2.0.0
  License: GPLv2
  DOC: Libs_Main|Libs/Main

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

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

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

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


ID: DevLib
NAME: 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.

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

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

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


ID: PrescrTempl
NAME: Prescriptions
uk#NAME: Шаблони рецепту
DB: tmplib_PrescrTempl
ru#NAME: Шаблоны рецепта
DESCR:
  Library of the prescriptions.

  Author: Roman Savochenko <roman@oscada.org>
  Founded: April 2012
  Version: 1.0.0
  License: GPLv2
  DOC: Libs_Prescriptions|Libs/Prescriptions


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

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


# UserFuncLibs

ID: techApp
NAME: Technological devices
DB: techApp
uk#NAME: Технологічні апарати
ru#NAME: Технологические аппараты
DESCR:
  Library of models of the technological apparatuses.

  Founded: October 2005
  Author: Roman Savochenko <roman@oscada.org>, Maxim Lysenko (2007,2010), Ksenia Yashina (2007)
  Version: 2.0.0
  License: GPL
  DOC: Libs_Technological_apparatuses|Libs/Technological_apparatuses

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

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

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

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


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

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

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

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

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

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


ID: doc
NAME: Report's documents
DB: flb_doc
uk#NAME: Звітна документація
ru#NAME: Отчётная документация
DESCR:
  Library of functions to facilitate the implementation of typical computations the primitive form of reporting documentation VCA "Document".

  Founded: January 2008
  Author: Roman Savochenko <roman@oscada.org>
  Version: 1.1.0
  License: GPL

uk#DESCR:
  Бібліотека функцій для полегшення виконання типових обчислень примітиву формування звітної документації СВУ "Документ".

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

ru#DESCR:
  Библиотека функций для облегчения выполнения типовых вычислений примитива формирования отчётной документации СВУ "Документ".

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


ID: regEl
NAME: Regulation elements
DB: flb_regEl
uk#NAME: Елементи регулювання
ru#NAME: Элементы регулирования
DESCR:
  Regulation elements library.

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

uk#DESCR:
  Бібліотека елементів регулювання.

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

ru#DESCR:
  Библиотека элементов регулирования.

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


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.1.0
  License: GPL

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

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

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

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


# 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
  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,ru,uk:How_to.html
  Documents/How_to/Install:en,ru,uk:How_to_Install.html
  Documents/How_to/Live_disk:en,ru,uk:How_to_Live_disk.html
  Documents/How_to/Violations,_alarms_and_notifications:en,ru,uk:How_to_Violations.html
  Documents/How_to/Cyclic_programming:en,ru,uk:How_to_Cyclic_programming.html
  Documents/How_to/Debug:en,ru,uk:How_to_Debug.html
  Documents/How_to/Transferring_project_configuration:en,ru,uk:How_to_Transferring_project_configuration.html
  Documents/How_to/Build_from_source:en,ru,uk:How_to_Build_from_source.html
  Documents/How_to/Crash_report:en,ru,uk:How_to_Crash_report.html
  Documents/How_to/Create_module:en,ru,uk: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/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:Libs_Main.html
  Libs/Technological_apparatuses:en,uk,ru:Libs_Technological_apparatuses.html


# flb_web_io

F_ID: diagram
ID: tmpl
NAME: SVG-template
DEF:
  <svg xmlns="http://www.w3.org/2000/svg" version="1.1" style="font-family: Times; font-size: 12px;">
      <style type="text/css">
  	    #scVert rect { fill: gray; stroke: none; }
  	    #scVert text { fill: gray; stroke: none; }
  	    #scHor rect { fill: gray; stroke: none; }
  	    #scHor text { fill: gray; stroke: none; }
  	    #drawArea path { stroke-width: 1; fill: none; }
      </style>
      <!--Draw grid and markers-->
      <g id="scVert" />
      <g id="scHor" />
      <!--Curves area -->
      <g id="drawArea" />
  </svg>


# 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.


# tmplib_DevLib

ID: SCU750
NAME: EDWARDS TURBOMOLECULAR PUMPS
DESCR:
  Typical EDWARDS TURBOMOLECULAR PUMPS (http://edwardsvacuum.com) data request 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

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

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:
  Multichannels thermometer Elemer TM5102 and TM5103 of firm Elemer (http://www.elemer.ru).
  Author: Roman Savochenko <roman@oscada.org>
  Version: 1.0.0

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("NORMA"), 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

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 its 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

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

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

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

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

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_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 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>
  Sponsored: Ustijancev Michael
  Version: 1.3.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>
  Спонсорування: Устьянцев Михайло
  Версія: 1.3.0
  Ліцензія: GPLv2

PROGRAM:
  JavaLikeCalc.JavaScript
  using Special.FLibSYS;

  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)	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 == "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 = -1;// 1;	//ActTerm, repeate after 1 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++;
  					SIQ = bufIn.charCodeAt(iOff);
  					aid = "di"+IOA;
  					if(items[aid].isEVal()) {
  						items[aid] = itW = new Object();
  						itW.descr = "DI["+IOA+"]";
  						itW.wr = false; itW.alarm = 0;
  					}
  					items[aid].val = SIQ&0x01;
  					items[aid].SIQ = SIQ;	//For a specific quality processing
  					if((aO=this[aid])) aO.set(items[aid].val, 0, 0, true);
  				}
  			}
  			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;
  					SIQ = bufIn.charCodeAt(iOff+2);
  					aid = "ai"+IOA;

  					if(items[aid].isEVal()) {
  						items[aid] = itW = new Object();
  						itW.descr = "AI["+IOA+"]";
  						itW.wr = false; itW.alarm = 0;
  					}
  					items[aid].val = val;
  					items[aid].SIQ = SIQ;	//For specific quality processing
  					if((aO=this[aid])) aO.set(items[aid].val, 0, 0, true);
  				}
  			}
  			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++;
  					val = floatMergeWord(bufIn.charCodeAt(iOff+1)*256+bufIn.charCodeAt(iOff), bufIn.charCodeAt(iOff+3)*256+bufIn.charCodeAt(iOff+2));
  					SIQ = bufIn.charCodeAt(iOff+4);
  					aid = "ai"+IOA;

  					if(items[aid].isEVal()) {
  						items[aid] = itW = new Object();
  						itW.descr = "AI["+IOA+"]";
  						itW.wr = false; itW.alarm = 0;
  					}

  					items[aid].val = val;
  					items[aid].SIQ = SIQ;	//For specific quality processing
  					if((aO=this[aid]))	aO.set(items[aid].val, 0, 0, true);
  				}
  			}
  			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++;
  					val = floatMergeWord(bufIn.charCodeAt(iOff+1)*256+bufIn.charCodeAt(iOff), bufIn.charCodeAt(iOff+3)*256+bufIn.charCodeAt(iOff+2));
  					SIQ = bufIn.charCodeAt(iOff+4);
  					aid = "ai"+IOA;

  					if(items[aid].isEVal()) {
  						items[aid] = itW = new Object();
  						itW.descr = "AI["+IOA+"]";
  						itW.wr = false; itW.alarm = 0;
  					}
  					// Getting the timestamp
  					ttm_ms = bufIn.charCodeAt(iOff+6)*256 + bufIn.charCodeAt(iOff+5);
  					ttm = SYS.mktime(ttm_ms/1000, bufIn.charCodeAt(iOff+7)&0x3F, bufIn.charCodeAt(iOff+8)&0x1F,
  						bufIn.charCodeAt(iOff+9)&0x1F, (bufIn.charCodeAt(iOff+10)&0x0F)-1, 2000+(bufIn.charCodeAt(iOff+11)&0x7F));

  					items[aid].val = val;
  					items[aid].SIQ = SIQ;	//For specific quality processing
  					if((aO=this[aid])) {
  						aO.set(items[aid].val, 0, 0, true);
  						if(aO.arch())	aO.arch().setVal(1e6*ttm+1000*floor(ttm_ms/1000), items[aid].val);
  					}
  				}
  			}
  			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++;
  					SIQ = bufIn.charCodeAt(iOff);
  					aid = "do" + IOA;
  					items[aid].val = SIQ&0x01;
  					items[aid].SIQ = SIQ;	//For a specific quality processing
  					if((aO=this[aid])) { aO.set(items[aid].val, 0, 0, true); oAVals[aid] = items[aid].val; }
  				}
  				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

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 firm Incotex (http://www.incotexcom.ru).
  Author: Arsen Zakojan <godzilla919@gmail.com>
  Version: 1.0.0

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 firm Incotex (http://www.incotexcom.ru).
  Author: Arsen Zakojan <godzilla919@gmail.com>
  Version: 1.0.0

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

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.

  Author: Roman Savochenko <roman@oscada.org>
  Sponsored by: SVItoVYR LTD
  Version: 1.0.2
  License: GPLv2

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

  Автор: Роман Савоченко <roman@oscada.org>
  Спонсорування: ТОВ "СВІТоВИР"
  Версія: 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

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].
  The protocol implementing is not finished due to missing for feedback from the developer to resolve this undocumented behavior:
  - МВ110-8А responds error 0x31 for reading "in-t" >1003023331932DCB43 <1010932D4791;
  - and error 0x34 for it writing >1003023334932D2A42 <1001932D0BEDBC.
  Author: Roman Savochenko <roman@oscada.org>, Constantine (IrmIngeneer)
  Version: 0.8.1

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 part of the protocol DCON implementation with the input part designed for typical AI module at up to 20 channels.
  The DCON commands are supported: #AA
  Author: Roman Savochenko <roman@oscada.org>
  Version: 1.0.1

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 part of the protocol DCON implementation with the input part designed for typical DI module at up to 32 channels.
  The DCON commands are supported: @AA, $AA6
  Author: Roman Savochenko <roman@oscada.org>
  Version: 1.0.1

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 part of the protocol DCON implementation with the input part designed for typical AO module at up to 8 channels.
  The DCON commands are supported: $AA8N, #AAN{Data}
  Author: Roman Savochenko <roman@oscada.org>
  Version: 1.0.1

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 part of the protocol DCON implementation with the input part designed for typical DO module at up to 32 channels.
  The DCON commands are supported: @AA, @AA{Data}
  Author: Roman Savochenko <roman@oscada.org>
  Version: 1.0.1

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;


# tmplib_PrescrTempl

ID: timer
NAME: Timer
uk#NAME: Таймер
ru#NAME: Таймер
DESCR: Typical timer. Hold run up to time elapse.
uk#DESCR: Типовий таймер. Утримує виконання до завершення часу.
ru#DESCR: Типовой таймер. Удерживает выполнение до завершения времени.
PROGRAM:
  JavaLikeCalc.JavaScript
  //Reset to default
  if(f_start || (!run && tmp1)) { run = pause = error = abort = false; tmp1 = 0; rez = 1; }
  //Run
  if(run && !pause) {
  	if(tmp1 == 0) tmp1 = arg1+1/f_frq;
  	tmp1 = max(0, tmp1 - 1/f_frq);
  	if(tmp1 <= 0) { rez = "1:"+tr("Waiting %1s expired").replace("%1",arg1.toPrecision(3)); run = false; }
  	else rez = "0:"+tr("Waiting %1s").replace("%1",tmp1.toPrecision(3));
  }


ID: backTimer
NAME: Background timer
uk#NAME: Фоновий таймер
ru#NAME: Фоновый таймер
DESCR: Background timer. Updating parallel with current command.
uk#DESCR: Фоновий таймер. Оновлення паралельно із поточною командой.
ru#DESCR: Фоновый таймер. Обновление параллельно с текущей командой.
PROGRAM:
  JavaLikeCalc.JavaScript
  //Reset to default
  if(f_start || (!run && tmp1)) { run = pause = error = abort = false; tmp1 = 0; rez = 1; }
  //Run
  if(run && !pause) {
  	if(tmp1 == 0) tmp1 = arg1+1/f_frq;
  	tmp1 = max(0, tmp1 - 1/f_frq);
  	if(tmp1 <= 0) { rez = "1:"+tr("Waiting %1s expired").replace("%1",arg1.toPrecision(3)); run = false; }
  	//if(tmp1 <= 10)	rez = "-1:Waiting "+arg1.toPrecision(3)+"s expired";
  	else rez = "10:"+tr("Background waiting %1s").replace("%1",tmp1.toPrecision(3));
  }


ID: manager
NAME: Prescriptions manager
DESCR:
  Prescriptions manager and controller. Used in addition with user interface's cadre "Prescription: editing" and "Prescription: runtime" for which into a parameter of the controller you must pass that parameters: "mode", "prog", "startTm", "curCom", "comLs", "work".

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

PROGRAM:
  JavaLikeCalc.JavaScript
  clcCnt++;

  if(f_start)	work = SYS.XMLNode("prg");

  //Checking for the commands controller presence
  comCntrO = false;
  if(comsCntr.length)	comCntrO = (comsCntr=="*") ? this.nodePrev() : SYS.DAQ.nodeAt(comsCntr,".");

  //Commands list update
  if(f_start || !(clcCnt%(60*f_frq))) {
  	if(!comCntrO) {
  		rez = SYS.BD.nodeAt(dbDB,".").SQLReq("SELECT * FROM "+dbComs+";");
  		comLs = new Object();
  		for(i_t = 1; i_t < rez.length; i_t++) {
  			comNm = rez[i_t]["name"];
  			comLs[comNm] = new Object();
  			comLs[comNm]["descr"] = rez[i_t]["descr"];
  			comLs[comNm]["proc"] = rez[i_t]["proc"];
  			for(i_a = 1; i_a <= 5; i_a++)
  				comLs[comNm]["arg"+i_a] = rez[i_t]["arg"+i_a];
  		}
  	}
  	else {
  		var nL = comCntrO.nodeList("prm_");
  		comLs = new Object();
  		for(i_n = 0; i_n < nL.length; i_n++) {
  			comO = comCntrO[nL[i_n]];
  			if(!comO.nodeAt("start") || !comO.nodeAt("stop") || !comO.nodeAt("run"))	continue;
  			comNm = comO.cfg("NAME");
  			comLs[comNm] = new Object();
  			comLs[comNm]["prmID"] = nL[i_n].slice(4);
  			comLs[comNm]["descr"] = comO.cfg("DESCR");
  			for(i_a = 1; i_a <= 5; i_a++)
  				if(!(comA=comO["arg"+i_a]).isEVal())
  					comLs[comNm]["arg"+i_a] = comA.descr();
  		}
  	}
  }

  //Programm selection change
  if(curMode <= 0 && prog.length && (prog != work.attr("name") || mode == 1)) {
  	work = SYS.XMLNode("prg");
  	rez = SYS.BD.nodeAt(dbDB,".").SQLReq("SELECT prgTxt FROM "+dbProgs+" WHERE name='"+prog+"';");
  	if(rez.length > 1) {
  		//Parse program and insert procedure text and argument's labels
  		work.load(rez[1][0]);
  		work.setAttr("name",prog);
  		for(comElN = work, comPos = 0; true; comPos++) {
  			if(comPos >= comElN.childSize()) {
  				if((comElN=comElN.parent())) { comPos = comElN.attr("seekPos").toInt(); continue; }
  				break;
  			}
  			comElI = comElN.childGet(comPos);
  			comId = comElI.attr("id");
  			if(comLs[comId].isEVal())	continue;
  			comElI.setAttr("proc",comLs[comId].proc);
  			for(i_a = 1; i_a <= 5; i_a++) comElI.setAttr("labArg"+i_a,comLs[comId]["arg"+i_a]);
  			if(comElI.childSize()) { comElN.setAttr("seekPos",comPos); comElN = comElI; comPos = -1; }
  		}
  	}
  	else prog = "";
  }

  //Start process
  if(curMode <= 0 && mode == 1 && prog.length) {
  	startTm = SYS.time();
  	curCom = 0;
  	curMode = mode;	

  	if(comCntrO) {
  		var cL = comCntrO.nodeList("prm_");
  		for(i_c = 0; i_c < cL.length; i_c++) {
  			var cLi = comCntrO[cL[i_c]];
  			cLi.run.set(false);
  			cLi.stop.set(false);
  			cLi.error.set(false);
  			cLi.abort.set(false);
  			cLi.start.set(true);
  		}
  	}
  }
  //Pause and other process
  else if((mode == 0 && curMode < 0) || (curMode == 1 && mode == 2) || (curMode == 2 && (mode == 0 || mode == 1))) {
  	//curMode = mode;
  	if((mode == 0 || mode == 1 || mode == 2) && comCntrO) {
  		var cL = comCntrO.nodeList("prm_");
  		for(i_c = 0; i_c < cL.length; i_c++)
  			comCntrO[cL[i_c]].pause.set(mode==2);
  	}
  }

  //Call program
  if(curMode == 1 || curMode == 2) {
  	prog = work.attr("name");

  	//Curent node at levels obtain
  	curComNd = work;
  	for(curComLev = 0, curComPos = 0, off = 0; curComNd && (tVl=curCom.parse(0,":",off)).length; curComLev++, curComPos = tVl.toInt())
  		curComNd = curComNd.childGet(tVl.toInt());
  	if(!curComNd) {
  		SYS.messInfo("uprg"+prog,tr("No current node present")+" \""+prog+"\" : "+SYS.strftime(startTm)+" : "+SYS.strftime(SYS.time()));
  		curMode = mode = -3;
  	}
  	curComNd = curComNd.parent();

  	//Internal commands call
  	if(!comCntrO) {
  		//????
  		if(mode == 3 && curCom >= 0 && curCom < work.childSize()) {
  			work.childGet(curCom).setAttr("rez", "-10:"+tr("Step missed"));
  			curCom++;
  		}
  		if(curCom >= 0 && curCom < work.childSize()) {
  			comEl = work.childGet(curCom);
  			//Stop process
  			if(mode == 0) {
  				comEl.setAttr("rez","-10:"+tr("Program terminated"));
  				// Call stop command
  				if(!comLs["Stop"].isEVal()) {
  					off = 0;
  					prLang = comLs["Stop"].proc.parse(0,"\n",off);
  					SYS.DAQ.funcCall(prLang,new Object(),comLs["Stop"].proc.slice(off));
  				}
  				SYS.messInfo("uprg"+prog,tr("Terminated by user session of the program")+" \""+prog+"\" : "+SYS.strftime(startTm)+" : "+SYS.strftime(SYS.time()));
  				curMode = mode = -3;
  			}
  			//Pass empty command		
  			else if(!comEl.attr("proc").length) curCom++;
  			//Execute command
  			else if(curMode == 1) {
  				args = new Object();
  				args.rez = "";
  				args.f_start = !comEl.attr("tm").length;
  				if(args.f_start) comEl.setAttr("tm",SYS.time());
  				args.f_frq = f_frq;
  				for(i_a = 1; i_a <= 5; i_a++) args["arg"+i_a] = comEl.attr("arg"+i_a);
  				for(i_a = 1; i_a <= 10; i_a++) args["tmp"+i_a] = comEl.attr("tmp"+i_a);
  				off = 0;
  				prLang = comEl.attr("proc").parse(0,"\n",off);
  				rez = SYS.DAQ.funcCall(prLang,args,comEl.attr("proc").slice(off));
  				if(rez && args.rez.toInt() > 0) curCom++;
  				else if(!rez || args.rez.toInt() < 0) {
  					// Call error command
  					if(!comLs["Error"].isEVal()) {
  						off = 0;
  						prLang = comLs["Error"].proc.parse(0,"\n",off);
  						SYS.DAQ.funcCall(prLang,new Object(),comLs["Error"].proc.slice(off));
  					}
  					SYS.messInfo("uprg"+prog,tr("Terminated by error session of the program")+" \""+prog+"\" : "+SYS.strftime(startTm)+" : "+SYS.strftime(SYS.time()));
  					curMode = mode = -1;
  				}
  				comEl.setAttr("rez",args.rez);
  				for(i_a = 1; i_a <= 5; i_a++) comEl.setAttr("arg"+i_a, args["arg"+i_a]);
  				for(i_a = 1; i_a <= 10; i_a++) comEl.setAttr("tmp"+i_a, args["tmp"+i_a]);
  				//SYS.messDebug("TEST Calc","TEST Calc rezult: "+args.y);
  			}
  		}

  		//End call
  		if(curCom < 0 || curCom >= work.childSize()) {
  			// Call stop command
  			if(!comLs["Stop"].isEVal()) {
  				off = 0;
  				prLang = comLs["Stop"].proc.parse(0,"\n",off);
  				SYS.DAQ.funcCall(prLang,new Object(),comLs["Stop"].proc.slice(off));
  			}

  			curMode = mode = -2;
  			SYS.messInfo("uprg"+prog,tr("Successful session of the program")+" \""+prog+"\" : "+SYS.strftime(startTm)+" : "+SYS.strftime(SYS.time()));

  			//Place to program last execution time
  			rez = SYS.BD.nodeAt(dbDB,".").SQLReq("SELECT prgTxt FROM "+dbProgs+" WHERE name='"+prog+"';");
  			if(rez.length > 1) {
  				//Parse programm and insert procedure text and argument's labels to here
  				comTree = SYS.XMLNode("prg");
  				comTree.load(rez[1][0]);
  				comTree.setAttr("wtm",SYS.time()-startTm);
  				SYS.BD.nodeAt(dbDB,".").SQLReq("UPDATE "+dbProgs+" SET prgTxt='"+comTree.save().replace("'","''")+"' WHERE name='"+prog+"';");
  			}
  		}
  	}
  	//External commands call
  	else {
  		// Get current command parameter-object		
  		toNext = toStop = toPass = false;
  		isRun = actBackGrnd = false;

  		curComPrm = EVAL_BOOL;
  		if(curComPos >= 0 && curComPos < curComNd.childSize()) {
  			if(!(comId=comLs[curComNd.childGet(curComPos).attr("id")]).isEVal()) curComPrm = comCntrO["prm_"+comId.prmID];
  			if(curComPrm.isEVal()) {
  				curMode = mode = -1;
  				curComNd.childGet(curComPos).setAttr("rez","-11:"+tr("Command miss: ")+work.childGet(curCom).attr("id"));
  				return;
  			}
  		}
  		if(mode == 3 && curComPos >= 0 && curComPos < curComNd.childSize()) {
  			//curComNd.childGet(curComPos).setAttr("rez","-10:"+tr("Step missed"));
  			//curComPrm.run.set(false);
  			mode = curMode;
  			toNext = toPass = true;
  		}
  		else if(curComPos >= 0 && curComPos < curComNd.childSize()) {
  			comEl = curComNd.childGet(curComPos);

  			//Stop process
  			if(mode == 0) {
  				toStop = true;
  				//comEl.setAttr("rez","-12:"+tr("Program terminated"));
  				// Stop all typical and set "abort" flag
  				var cL = comCntrO.nodeList("prm_");
  				for(i_c = 0; i_c < cL.length; i_c++) {
  					var cLi = comCntrO[cL[i_c]];
  					cLi.run.set(false);
  					cLi.start.set(false);
  					cLi.abort.set(true);
  				}
  				SYS.messInfo("uprg"+prog, tr("Terminated by user session of the program")+" \""+prog+"\" : "+SYS.strftime(startTm)+" : "+SYS.strftime(SYS.time()));
  				curMode = mode = -3;
  			}
  			//Commands process
  			else {
  				// Start command
  				if(!comEl.attr("tm").length) {
  					curComPrm.run.set(false);	//Stop for possible background call
  					comEl.setAttr("tm", SYS.time());
  					for(i_a = 1; i_a <= 5; i_a++)
  						if(!(comA=curComPrm["arg"+i_a]).isEVal())
  							comA.set(comEl.attr("arg"+i_a));
  					curComPrm.rez.set(0);
  					curComPrm.run.set(true);
  					if(mode == 2) curComPrm.pause.set(true);
  				}
  				isRun = true;
  			}
  		}
  		//Update steps status, up to the current comand
  		isCurCmd = false;
  		for(comElN = work, comPos = 0, comLev = 0, comCur = true; isRun || toPass || toStop; comPos++) {
  			if(comPos >= comElN.childSize()) {
  				if((comElN=comElN.parent())) {
  					comLev--;
  					comPos = comElN.attr("seekPos").toInt();
  					comCur = comElN.attr("comCur").toInt();
  					continue;
  				}
  				if(actBackGrnd && toNext) toNext = false;
  				break;
  			}
  			comElI = comElN.childGet(comPos);
  			isBackgrnd = comElI.attr("backgrnd").toInt();
  			if(!isBackgrnd && actBackGrnd)	toNext = false;
  			if(isCurCmd) break;
  			isCurCmd = comCur && comLev == (curComLev-1) && curCom.parse(comLev,":").toInt() == comPos;
  			curComPI = comCntrO["prm_"+comLs[comElI.attr("id")].prmID];
  			rez = curComPI.rez.get();
  			if(isCurCmd || ((toStop || curComPI.run.get()) && comElI.attr("rez").toInt() != 1 && comElI.attr("rez").toInt() > -10)) {
  				if(toStop)	rez = "-12:" + tr("Program terminated");
  				else if(toPass) {
  					rez = "-10:" + tr("Step missed");
  					curComPI.run.set(false);
  				}
  				else if(rez.toInt() < 0) {
  					// Stop all typical and call "error" command
  					var cL = comCntrO.nodeList("prm_");
  					for(i_c = 0; i_c < cL.length; i_c++) {
  						var cLi = comCntrO[cL[i_c]];
  						cLi.run.set(false);
  						cLi.start.set(false);
  						cLi.error.set(true);
  					}
  					SYS.messInfo("uprg"+prog,tr("Terminated by error session of the program")+" \""+prog+"\" : "+SYS.strftime(startTm)+" : "+SYS.strftime(SYS.time()));
  					curMode = mode = -1;
  				}
  				if(!actBackGrnd && isBackgrnd && rez.toInt() == 0) actBackGrnd = true;
  				if(isCurCmd && (rez.toInt() > 0 || isBackgrnd) && !toStop)	toNext = true;
  				comElI.setAttr("rez", rez);
  				for(i_a = 1; i_a <= 5; i_a++)
  					if(!(comA=curComPI["arg"+i_a]).isEVal())
  						comElI.setAttr("arg"+i_a, comA.get());
  			}
  			if(isCurCmd) continue;
  			//Force backgrounded rezult update for running
  			if(rez.toInt() != 0 && comElI.attr("rez").toInt() == 0)	comElI.setAttr("rez", rez);

  			if(comElI.childSize()) {
  				comElN.setAttr("seekPos", comPos);
  				comElN.setAttr("comCur", comCur);
  				comElN = comElI;
  				comCur = comCur && comLev < curComLev && curCom.parse(comLev,":").toInt() == comPos;
  				comPos = -1; comLev++;
  			}
  		}

  		// Go to next step
  		if(toNext) {
  			if(curComNd.childGet(curComPos).childSize())	{ curComLev++; curComPos = 0; }
  			else if((++curComPos) >= curComNd.childSize())
  			{ curComLev--; curComPos = curComLev ? curCom.parse(curComLev-1,":").toInt()+1 : curComNd.childSize(); }
  			for(i_c = 0, curComN = ""; i_c < (curComLev-1); i_c++) curComN += curCom.parse(i_c,":");
  			curCom = curComN.length ? curComN+":"+curComPos : curComPos;
  		}
  		
  		//End call
  		if(curComLev <= 0) {
  			// Stop all typical and call "stop" command
  			var cL = comCntrO.nodeList("prm_");
  			for(i_c = 0; i_c < cL.length; i_c++) {
  				var cLi = comCntrO[cL[i_c]];
  				cLi.run.set(false);
  				cLi.start.set(false);
  				cLi.stop.set(true);
  			}

  			curMode = mode = -2;
  			SYS.messInfo("uprg"+prog,tr("Successful session of the program")+" \""+prog+"\" : "+SYS.strftime(startTm)+" : "+SYS.strftime(SYS.time()));

  			//Place to program last execution time
  			rez = SYS.BD.nodeAt(dbDB,".").SQLReq("SELECT prgTxt FROM "+dbProgs+" WHERE name='"+prog+"';");
  			if(rez.length > 1) {
  				//Parse program and insert procedure text and argument's labels to here
  				comTree = SYS.XMLNode("prg");
  				comTree.load(rez[1][0]);
  				comTree.setAttr("wtm",SYS.time()-startTm);
  				SYS.BD.nodeAt(dbDB,".").SQLReq("UPDATE "+dbProgs+" SET prgTxt='"+comTree.save().replace("'","''")+"' WHERE name='"+prog+"';");
  			}
  		}
  	}
  }
  curMode = mode;
  //mode = curMode;


# tmplib_base

ID: digAlarm
NAME: Alarm discrete
uk#NAME: Сигналізація дискретна
ru#NAME: Сигнализация дискретная
ru#DESCR:
  Сигнализация по дискретному параметру.

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

DESCR:
  Common, representative and unified template of separate discrete parameter (complex tag) processing with formation of signaling by the defined criterion. The template forms a structure of discrete parameter (complex tag) which can be easily connected to most widgets and cadres of the main elements library of the user interface just pointing the parameter object.

  The template provides some fields of the representative structure of the discrete parameters and adds the error field:
  - "State "Opened" (st_open)" — the state "Opened".
  - "State "Closed" (st_close)" — the state "Closed".
  - "Error (err)" — obligatory attribute of any parameter, consist of the combination of the error code and short text description, like to "2:No data or connection with source". The template reserves next error codes:
    - 1 — hardware errors, when the data mostly wrong;
    - 3 — violation of the specified condition.

  Functions:
  - Direct obtaining, by link, of the initial state and formation of two representative states with the possibility of their inversion stInv.
  - Complex preprocessing and complete generation-imitation of the discrete input on the internal programming language of OpenSCADA into the configuration IO inProc, where you can operate next service parameters:
    - in [IN|OUT] — the same raw discrete input IO;
    - levErr, tErr [IN|OUT] — alarm level [-7...0] and text of the error (the attribute "err" format);
    - f_frq [IN] — frequency of calculation, the template IO;
    - this [IN] — reference to the parameter object, what executing the template;
    - ctx [IN] — object of the user context, what saved between the execution cycles.
  - Processing of the discrete input in for the purpose of creating a violation and correspondingly setting the attribute err, at the condition "{st}:{lev}:{mess}", that is generation violation of the level lev and the text mess for the input status st (0|1).

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

uk#DESCR:
  Загальний, представницький шаблон обробки окремого дискретного параметру (складного тегу) із формування сигналізації за визначеним критерієм. Шаблон формує структуру дискретного параметру (складного тегу) який може бути легко підключений до більшості віджетів та кадрів бібліотеки основних елементів інтерфейсу користувача просто вказавши об'єкт параметру.

  Шаблон надає окремі поля представницької структури дискретного параметру та додає поле помилки:
  - "Стан "Відкрито" (st_open)" — стан "Відкрито".
  - "Стан "Закрито" (st_close)" — стан "Відкрито".
  - "Помилка (err)" — обов'язковий атрибут будь якого параметру, що містить комбінацію коду помилки та короткого опису, на кшталт "1:Немає даних або підключення до джерела". Шаблон резервує наступні коди помилок:
    - 1 — помилки обладнання, коли дані переважно помилкові;
    - 3 — порушення за визначеної умови.

  Функції
  - Пряме отримання, за посиланням, первинного стану та формування двох репрезентативних станів з можливістю їх інверсії stInv.
  - Складна передобробка та повна генерація-імітація дискретного входу на внутрішній мові програмування OpenSCADA у конфігураційному ВВ inProc, де Ви можете оперувати наступними сервісними параметрами:
    - in [IN|OUT] — той самий сирий дискретний ВВ;
    - levErr, tErr [IN|OUT] — рівень аварії [-7...0] та текст помилки (формат атрибуту "err");
    - f_frq [IN] — частота обчислення, шаблонний ВВ;
    - this [IN] — посилання на об'єкт параметру, що виконує шаблон;
    - ctx [IN] — об'єкт користувацького контексту, що зберігається між циклами виклику.
  - Опрацювання дискретного входу in на предмет формування порушення та відповідного встановлення атрибуту err, за умови "{st}:{lev}:{mess}", тобто генерація порушення з рівнем lev та текстом mess за стану входу st (0|1).

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

PROGRAM:
  JavaLikeCalc.JavaScript
  if(f_start) {
  	f_err = "0";
  	alDelay_ = 0;
  	//Prepare data for preprocessing
  	inPrcId = this.nodePath("_");
  	inPrcLng = "JavaLikeCalc.JavaScript";
  	inPrcArgs = new Object();
  	inPrcArgs.this = this;
  	inPrcArgs.ctx = new Object();
  	return;
  }
  if(f_stop) return;

  tErr = "0", levErr = 0;

  //Call a specific preprocessing procedure
  if(inProc.length)	{
  	inPrcArgs.f_frq = f_frq;
  	inPrcArgs.in = in;
  	inPrcArgs.levErr = levErr; inPrcArgs.tErr = tErr;
  	SYS.DAQ.funcCall(inPrcLng, inPrcArgs, inProc, inPrcId);
  	levErr = inPrcArgs.levErr; tErr = inPrcArgs.tErr;
  	in = inPrcArgs.in;
  }

  //State set
  if(in.isEVal()) {
  	tErr = "1:"+tr("No data or connection with source");
  	levErr = -5;
  	st_open = st_close = in;
  }
  else {
  	if(alrm.length && in == alrm.toInt())
  		tErr = "3:"+alrm.parse(2,":"), levErr = -alrm.parse(1,":").toInt();
  	st_open = stInv ? !in : in;
  	st_close = !st_open;
  }

  //Alarms forming
  if(alSup) {
  	if(f_err.toInt())	this.alarmSet(DESCR+": "+tr("SUPPRESSED"), 1);
  	f_err = "0";
  }
  else {
  	if(tErr.toInt() && tErr.toInt() != f_err.toInt() && this.cntr().status().toInt())	return;
  	if(alDelay > 0 && alDelay_ <= 0 && tErr.toInt() != f_err.toInt())	tErr1 = tErr.toInt();
  	if(alDelay > 0 && alDelay_ > 0 && tErr.toInt() != tErr1)	{ alDelay_ = 0; tErr1 = tErr.toInt(); }
  	if(alDelay > 0 && alDelay_ < alDelay){ alDelay_ += 1/f_frq; return; }
  	if(tErr.toInt())	this.alarmSet(DESCR+": "+tErr.parse(1,":"), levErr);
  	else	this.alarmSet(DESCR+": "+tr("NORMA"), 1);
  	f_err = tErr;
  	alDelay_ = 0;
  }


ID: simleBoard
NAME: Analog alarm by borders (obsolete)
uk#NAME: Сигнал аналоговий за границями (застаріле)
ru#NAME: Сигнал аналоговый по границам (устаревшее)
DESCR:
  The template of simple parameter included borders and dimension variable.

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

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

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

ru#DESCR:
  Шаблон простого параметра с проверкой границ и единицей измерения.

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

PROGRAM:
  JavaLikeCalc.JavaScript
  var=iMult*(in+iAdd);
  if(var>max)			f_err="1:Upper work border violation";
  else if(var<min)			f_err="2:Bottom work border violation";
  else if(aMax>aMin && var>aMax)		f_err="3:Upper alarm border violation";
  else if(aMax>aMin && var<aMin)		f_err="4:Bottom alarm border violation";
  else if(wMax>wMin && var>wMax)	f_err="5:Upper warning border violation";
  else if(wMax>wMin && var<wMin)	f_err="6:Bottom warning border violation";
  else f_err="0";

uk#PROGRAM:
  JavaLikeCalc.JavaScript
  var=iMult*(in+iAdd);
  if(var>max)			f_err="1:Порушення верхньої робочої границі";
  else if(var<min)			f_err="2:Порушення нижньої робочої границі";
  else if(aMax>aMin && var>aMax)		f_err="3:Порушення верхньої аварійної границі";
  else if(aMax>aMin && var<aMin)		f_err="4:Порушення нижньої аварійної границі";
  else if(wMax>wMin && var>wMax)	f_err="5:Порушення верхньої попереджувальної границі";
  else if(wMax>wMin && var<wMin)	f_err="6:Порушення нижньої попереджувальної границі";
  else f_err="0";

ru#PROGRAM:
  JavaLikeCalc.JavaScript
  var=iMult*(in+iAdd);
  if(var>max)		f_err="1:Нарушение верхней рабочей границы";
  else if(var<min)	f_err="2:Нарушение нижней рабочей границы";
  else if(aMax>aMin && var>aMax)	f_err="3:Нарушение верхней аварийной границы";
  else if(aMax>aMin && var<aMin)	f_err="4:Нарушение нижней аварийной границы";
  else if(wMax>wMin && var>wMax)	f_err="5:Нарушение верхней предупредительной границы";
  else if(wMax>wMin && var<wMin)	f_err="6:Нарушение нижней предупредительной границы";
  else f_err="0";


ID: digitBlock
NAME: Discrete parameters block (obsolete)
uk#NAME: Блок дискр. параметрів (застаріле)
ru#NAME: Блок дискр. параметров
DESCR:
  The block for union of Discrete parameters for one device control.

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

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

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

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

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

PROGRAM:
  JavaLikeCalc.JavaScript
  set = false;
  if(cmdOpen && !(last_cmd&0x1))	{ last_cmd = last_cmd|0x1; set = true; }
  if(cmdClose && !(last_cmd&0x2))	{ last_cmd = last_cmd|0x2; set = true; }
  if(cmdStop && !(last_cmd&0x4))	{ last_cmd = last_cmd|0x4; set = true; }
  if(set && tCmd > 0) w_tm = tCmd;
  if(w_tm > 0) w_tm -= 1/f_frq;
  else {
  	w_tm = 0;
  	if(tCmd > 0) {
  		if(last_cmd&0x1) { cmdOpen = false; last_cmd = last_cmd&(~0x1); }
  		if(last_cmd&0x2) { cmdClose = false; last_cmd = last_cmd&(~0x2); }
  		if(last_cmd&0x4) { cmdStop = false; last_cmd = last_cmd&(~0x4); }
  	}
  }


ID: gasPoint
NAME: Flow control point (obsolete)
uk#NAME: Витрато-вимірювальний вузол (застаріле)
ru#NAME: Расходомерный узел (устаревшее)
PROGRAM:
  JavaLikeCalc.JavaScript
  if(f_start)	Q = 0;
  //F=200+(rand(5)-2.5);
  Q += F.isEVal() ? 0 : F/3600;
  //P=9+(rand(2)-1);
  //T=15+(rand(2)-1);
  dP = F.isEVal() ? 0 : F/33;
  DS = 1+(rand(0.2)-0.1);


ID: manInUnif
NAME: Manual input (unified)
uk#NAME: Ручний ввід (уніфікований)
ru#NAME: Ручной ввод (унифицированный)
DESCR:
  Common, representative and unified template of a manual input — an analog output signal.
  The template forms a structure of parameter (complex tag) of the analog output which can be easily connected to most widgets and cadres of the main elements library of the user interface just pointing the parameter object, mostly through the Element cadre control panel.

  Functions:
  Mostly the same as the basic template "Analog signal (unified)" and the value entering attribute is additionally provided.

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

uk#DESCR:
  Загальний, представницький та уніфікований шаблон ручного вводу — сигналу аналогового виходу.
  Шаблон формує структуру параметру (складного тегу) аналогового виходу який може бути легко підключений до більшості віджетів та кадрів бібліотеки основних елементів інтерфейсу користувача просто вказавши об'єкт параметру, переважно через панель контролю Елемент кадр.

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

ru#DESCR:
  Унифицированный шаблон ручного ввода сигнала.

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

PROGRAM:
  JavaLikeCalc.JavaScript
  if(f_start)	{ f_err = "0"; alDelay_ = 0; }

  pMax = plcMax; pMin = plcMin;	//Copy for local modifies using
  if(passIn=(pMax==pMin)) { pMax = max/iMult - iAdd; pMin = min/iMult - iAdd; }

  //Manual input set process
  if(!varIn.isEVal() && (varIn != var || inout.isEVal())) {
  	if(passIn) { pMin = iMult*(pMin+iAdd); pMax = iMult*(pMax+iAdd); }
  	vCalibr = (varIn-min)/(max-min);
  	if(scSqr)	vCalibr = pow(vCalibr,2);
  	if(pMax < pMin) vCalibr = 1-vCalibr;
  	vCalibr = min(pMax,pMin)+vCalibr*abs(pMax-pMin);
  	inout = vCalibr/iMult - iAdd;
  }

  levErr = 0;
  tErr = "0";
  //Input data check and postprocess
  if(inout > (max(pMax,pMin)+plcExcess*abs(pMax-pMin)/100)) {
  	tErr = "1:"+tr("The signal exceed to upper hardware border"); levErr = -5;
  	var = max + plcExcess*(max-min)/100;
  }
  else if(inout < (min(pMax,pMin)-plcExcess*abs(pMax-pMin)/100)) {
  	tErr = "2:"+tr("The signal exceed to bottom hardware border"); levErr = -5;
  	var = min - plcExcess*(max-min)/100;
  }
  if(!tErr) {
  	vCalibr = iMult*(inout+iAdd);
  	if(passIn) { pMin = iMult*(pMin+iAdd); pMax = iMult*(pMax+iAdd); }
  	if(!passIn || scSqr) {
  		vCalibr = (vCalibr-min(pMax,pMin))/abs(pMax-pMin);
  		if(pMax < pMin) vCalibr = 1-vCalibr;
  		vCalibr = min + (max-min)*(scSqr?pow(vCalibr,0.5):vCalibr);
  	}
  	if(var.isEVal())	var = vCalibr;
  	varDt = vCalibr - var;
  	var += varDt/max(1,Tf*f_frq);
  	varIn = var;

  	bndVarHyst = (max-min)*HystBnd/100;
  	if(aMax < max && aMax > aMin && (var >= aMax || (f_err.toInt() == 3 && var >= (aMax-bndVarHyst))))
  	{ tErr="3:"+tr("Upper alarm border error"); levErr = -4; }
  	else if(aMin > min && aMax > aMin && (var <= aMin || (f_err.toInt() == 4 && var <= (aMin+bndVarHyst))))
  	{ tErr="4:"+tr("Lower alarm border error"); levErr = -4; }
  	else if(wMax < max && wMax > wMin && (var >= wMax || (f_err.toInt() == 5 && var >= (wMax-bndVarHyst))))
  	{ tErr="5:"+tr("Upper warning border error"); levErr = -2; }
  	else if(wMin > min && wMax > wMin && (var <= wMin || (f_err.toInt() == 6 && var <= (wMin+bndVarHyst))))
  	{ tErr="6:"+tr("Lower warning border error"); levErr = -2; }
  	else if(speed && varDt > speed)	{ tErr="7:"+tr("Too big parameter's motion speed"); levErr = -2; }
  }

  //Alarms forming
  if(alSup) {
  	if(f_err.toInt())	this.alarmSet(DESCR+": "+tr("SUPPRESSED"), 1);
  	f_err = "0";
  }
  else {
  	if(tErr.toInt() && tErr.toInt() != f_err.toInt() && this.cntr().status().toInt())	return;
  	if(alDelay > 0 && alDelay_ <= 0 && tErr.toInt() != f_err.toInt())	tErr1 = tErr.toInt();
  	if(alDelay > 0 && alDelay_ > 0 && tErr.toInt() != tErr1)	{ alDelay_ = 0; tErr1 = tErr.toInt(); }
  	if(alDelay > 0 && alDelay_ < alDelay){ alDelay_ += 1/f_frq; return; }
  	if(tErr.toInt())	this.alarmSet(DESCR+": "+tErr.parse(1,":"), levErr);
  	else	this.alarmSet(DESCR+": "+tr("NORMA"), 1);
  	f_err = tErr;
  	alDelay_ = 0;
  }


ID: anUnif
NAME: Analog signal (unified)
uk#NAME: Аналоговий сигнал (уніфікований)
ru#NAME: Аналоговый сигнал (унифицированный)
DESCR:
  Common, representative and unified template of analog input signals processing. The template forms a structure of complex analog parameter (tag) which can be easily connected to most widgets and cadres of the main elements library of the user interface just pointing the parameter object.
  Functions:
  - Generic processing of the raw analog input for:
    - simple correction-calibration at the formula "in = iMult*(in+iAdd)";
    - scaling from the hardware border [plcMin...plcMax] to the main border [min...max], applying the square scale scSqr;
       !!! The hardware borders can be inverted ones and disabled in whole for equal values of the maximum and minimum, when the main border only used.
    - permission to exceed the border for the input value on the value of plcExcess percent;
    - filtering the input value changing in the time Tf.
  - Simple imitation of the analog input, setting plcImit and linking the imitation-simulation source in plcImitIn.
       !!! Missing the link plcImitIn (EVAL) causes to generating random analog input
  - Complex preprocessing and complete generation-imitation of the analog input on the internal programming language of OpenSCADA into the configuration IO inProc, where you can operate next service parameters:
    - f_frq [IN] — frequency of calculation, the template IO;
    - in [IN|OUT] — the same raw analog input IO;
    - var [IN] — the end variable IO;
    - min, max [IN] — the main border IOs;
    - plcMin, plcMax [IN] — the hardware border IOs;
    - plcImit, plcImitIn [IN] — IOs of the simple imitation;
    - levErr, tErr [IN|OUT] — alarm level [-7...0] and text of the error (the attribute "err" format).
  - Simple substitution for the variable subVar at the error (not valid) input variable (EVAL) in the modes: "no", "last" and "substitute".
  - Processing the result variable var for violation some borders and criteria, generating the alarms and proper setting the attribute err. The alarm borders can have some hysteresis HystBnd, can be delayed for the time alDelay and can be worked in the modes alSup: "init NORM", "suppress", "save on change". Next borders and criteria are provided:
    - missing for data or connection with source at the EVAL input value — error code 1 and alarm level 5;
    - exceeding the input value of the hardware border — error code 1,2 and alarm level 5;
    - exceeding the end variable of the alarm border [aMin...aMax] — error code 3,4 and alarm level 4;
       !!! Disabled at setting for equal or inverted values of the border
    - exceeding the end variable of the warning border [wMin...wMax] — error code 5,6 and alarm level 2;
       !!! Disabled at setting for equal or inverted values of the border
    - big motion speed of the end variable — error code 7 and alarm level 2.

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

uk#DESCR:
  Загальний, представницький та уніфікований шаблон обробки аналогових вхідних сигналів. Шаблон формує структуру складного аналогового параметру (тегу) який може бути легко підключений до більшості віджетів та кадрів бібліотеки основних елементів інтерфейсу користувача просто вказавши об'єкт параметру.
  Функції:
  - Загальне опрацювання аналогового входу щодо:
    - проста корекція-калібрування за формулою "in = iMult*(in+iAdd)";
    - масштабування від апаратної границі [plcMin...plcMax] у головну границю [min...max], враховуючи квадратичну шкалу scSqr;
       !!! Апаратні границі може бути інвертовано та взагалі вимкнено однаковими значеннями максимуму та мінімуму, коли використовується тільки головна шкала.
    - дозвіл на перевищення границі вхідним значенням на величину plcExcess відсотків;
    - фільтрування зміни вхідного значення на час Tf.
  - Проста імітація аналогового входу, встановленням plcImit та підключенням джерела імітації-симуляції до plcImitIn.
       !!! Відсутність зв'язка plcImitIn (EVAL) призводить до генерації випадкового аналогового входу
  - Складна передобробка та повна генерація-імітація аналогового входу на внутрішній мові програмування OpenSCADA у конфігураційному ВВ inProc, де Ви можете оперувати наступними сервісними параметрами:
    - f_frq [IN] — частота обчислення, шаблонний ВВ;
    - in [IN|OUT] — той самий сирий аналоговий ВВ;
    - var [IN] — ВВ кінцевої змінної;
    - min, max [IN] — ВВ головної шкали;
    - plcMin, plcMax [IN] — ВВ апаратної шкали;
    - plcImit, plcImitIn [IN] — ВВ простої імітації;
    - levErr, tErr [IN|OUT] — рівень аварії [-7...0] та текст помилки (формат атрибуту "err").
  - Проста підстановка значення subVar за помилкою (недостовірністю) вхідної змінної (EVAL) у режимах: "немає", "останнє" та "підстановка".
  - Опрацювання кінцевої змінної var на предмет порушення деяких границь та критеріїв, генеруючи аварії та відповідно встановлюючи атрибут err. Границі аварії можуть мати деякий гістерезис HystBnd, можуть бути затримані на час alDelay та можуть працювати у режимах alSup: "ініціювати НОРМА", "придушувати", "зберігати при зміні". Надаються наступні границі та критерії:
    - відсутність даних або підключення до джерела за вхідним значенням EVAL — код помилки 1 та рівень аварії 5;
    - перевищення апаратної границі вхідним значенням — код помилки 1,2 та рівень аварії 5;
    - перевищення аварійної границі кінцевою змінною [aMin...aMax] — код помилки 3,4 та рівень аварії 4;
       !!! Вимикається встановленням однакових або інверсних значень границі
    - перевищення попереджувальної границі кінцевою змінною [wMin...wMax] — код помилки 5,6 та рівень аварії 2;
       !!! Вимикається встановленням однакових або інверсних значень границі
    - велика швидкість зміни speed кінцевої змінної — код помилки 7 та рівень аварії 2.

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

ru#DESCR:
  Общий, представительский и унифицированный шаблон обработки аналоговых входных сигналов. Шаблон формирует структуру сложного аналогового параметра (тега) который может быть легко подключенный к большинству виджетов и кадров библиотеки основных элементов интерфейса пользователя просто указав объект параметра.

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

PROGRAM:
  JavaLikeCalc.JavaScript
  if(f_start) {
  	prevVar = EVAL_REAL;
  	alDelay_ = 0;
  	//Prepare data for preprocessing
  	inPrcId = this.nodePath("_");
  	inPrcLng = "JavaLikeCalc.JavaScript";
  	inPrcArgs = new Object();
  	inPrcArgs.this = this;
  	inPrcArgs.ctx = new Object();
  	return;
  }
  if(f_stop) return;

  pMax = plcMax; pMin = plcMin;	//Copy for local modifies using
  if(passIn=(pMax==pMin)) { pMax = max/iMult - iAdd; pMin = min/iMult - iAdd; }

  if(plcImit) {	//Data imitation
  	if(!plcImitIn.isEVal()) in = plcImitIn;
  	else {
  		var plcOff;
  		plcDif = abs(pMax-pMin);
  		if(plcOff.isEVal())		plcOff = rand(plcDif/2);
  		in = pMin + plcDif/4 + plcOff + rand(plcDif/10)-plcDif/20;
    }
  }

  levErr = 0;
  tErr = "0";

  //Call specific preprocessing procedure
  if(inProc.length)	{
  	inPrcArgs.f_frq = f_frq;
  	inPrcArgs.in = in; inPrcArgs.var = var; inPrcArgs.min = min; inPrcArgs.max = max;
  	inPrcArgs.plcMin = pMin; inPrcArgs.plcMax = pMax;
  	inPrcArgs.plcImit = plcImit; inPrcArgs.plcImitIn = plcImitIn;
  	inPrcArgs.levErr = levErr; inPrcArgs.tErr = tErr;
  	SYS.DAQ.funcCall(inPrcLng, inPrcArgs, inProc, inPrcId);
  	in = inPrcArgs.in;
  	levErr = inPrcArgs.levErr; tErr = inPrcArgs.tErr;
  }

  //Input data check and postprocess
  if(in.isEVal()) {
  	tErr = "1:"+tr("No data or connection with source"); levErr = -5;
  	var = EVAL_REAL;
  	if(subMode == 1) var = prevVar;
  	else if(subMode == 2) var = subVar;
  }
  else if(in > (max(pMax,pMin)+plcExcess*abs(pMax-pMin)/100)) {
  	tErr = "1:"+tr("The signal exceed to upper hardware border"); levErr = -5;
  	var = EVAL_REAL;
  	if(subMode == 1) var = prevVar.isEVal() ? max+plcExcess*(max-min)/100 : prevVar;
  	else if(subMode == 2) var = subVar;
  }
  else if(in < (min(pMax,pMin)-plcExcess*abs(pMax-pMin)/100)) {
  	tErr = "2:"+tr("The signal exceed to bottom hardware border"); levErr = -5;
  	var = EVAL_REAL;
  	if(subMode == 1) var = prevVar.isEVal() ? min-plcExcess*(max-min)/100 : prevVar;
  	else if(subMode == 2) var = subVar;
  }
  else {
  	vCalibr = iMult*(in+iAdd);
  	if(passIn) { pMin = iMult*(pMin+iAdd); pMax = iMult*(pMax+iAdd); }
  	if(!passIn || scSqr) {
  		vCalibr = (vCalibr-min(pMax,pMin))/abs(pMax-pMin);
  		if(pMax < pMin) vCalibr = 1-vCalibr;
  		vCalibr = min + (max-min)*(scSqr?pow(vCalibr,0.5):vCalibr);
  	}
  	if(var.isEVal())	var = vCalibr;
  	varDt = vCalibr - var;
  	var += varDt/max(1,Tf*f_frq);
  	prevVar = var;

  	if(!tErr) {
  		bndVarHyst = (max-min)*HystBnd/100;
  		if(aMax < max && aMax > aMin && (var >= aMax || (f_err.toInt() == 3 && var >= (aMax-bndVarHyst))))
  		{ tErr = "3:"+tr("Upper alarm border error"); levErr = -4; }
  		else if(aMin > min && aMax > aMin && (var <= aMin || (f_err.toInt() == 4 && var <= (aMin+bndVarHyst))))
  		{ tErr = "4:"+tr("Lower alarm border error"); levErr = -4; }
  		else if(wMax < max && wMax > wMin && (var >= wMax || (f_err.toInt() == 5 && var >= (wMax-bndVarHyst))))
  		{ tErr = "5:"+tr("Upper warning border error"); levErr = -2; }
  		else if(wMin > min && wMax > wMin && (var <= wMin || (f_err.toInt() == 6 && var <= (wMin+bndVarHyst))))
  		{ tErr = "6:"+tr("Lower warning border error"); levErr = -2; }
  		else if(speed && varDt > speed)	{ tErr = "7:"+tr("Too big parameter's motion speed"); levErr = -2; }
  	}
  }

  //Alarms forming
  if(alSup) {
  	if(f_err.toInt())	this.alarmSet(DESCR+": "+tr("SUPPRESSED"), 1);
  	f_err = "0";
  }
  else {
  	if(tErr.toInt() && tErr.toInt() != f_err.toInt() && this.cntr().status().toInt())	return;
  	if(alDelay > 0 && alDelay_ <= 0 && tErr.toInt() != f_err.toInt())	tErr1 = tErr.toInt();
  	if(alDelay > 0 && alDelay_ > 0 && tErr.toInt() != tErr1)	{ alDelay_ = 0; tErr1 = tErr.toInt(); }
  	if(alDelay > 0 && alDelay_ < alDelay){ alDelay_ += 1/f_frq; return; }
  	if(tErr.toInt())	this.alarmSet(DESCR+": "+tErr.parse(1,":"), levErr);
  	else	this.alarmSet(DESCR+": "+tr("NORMA"), 1);
  	f_err = tErr;
  	alDelay_ = 0;
  }


ID: digitBlockUnif
NAME: Discrete block (unified)
uk#NAME: Блок дискретних (уніфікований)
ru#NAME: Блок дискретных (унифицированный)
DESCR:
  Common, representative and unified template of the block for union of Discrete parameters for the common control device.
  The template forms a structure of discrete parameter-block (complex tag) which can be easily connected to most widgets and cadres of the main elements library of the user interface just pointing the parameter object.
  Functions:
  - Direct obtaining, by link, two states (read only) and three commands (reading and writing).
  - Possibility of holding the commands for a certain time and removing them.
  - Ability to redefine the states and commands by the appropriate settings of the interface elements, such as digStts, for statuses, and digComs, for commands.

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

uk#DESCR:
  Загальний, представницький та уніфікований шаблон блоку поєднання дискретних параметрів у пристрій загального контролю.
  Шаблон формує структуру дискретного параметру-блоку (складного тегу) який може бути легко підключений до більшості віджетів та кадрів бібліотеки основних елементів інтерфейсу користувача просто вказавши об'єкт параметру.
  Функції:
  - Пряме отримання, за посиланням, двох станів (тільки читання) та трьох команд (читання та запис).
  - Можливість утримання команди протягом визначеного часу та зняття їх.
  - Можливість перевизначення станів та команд відповідним налаштуванням елементів інтерфейсу, як то digStts, для статусів, та digComs, для команд.

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

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

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

PROGRAM:
  JavaLikeCalc.JavaScript
  set = false;
  if(!com.isEVal() && com && last_cmd != 1)		last_cmd = 1, set = true;
  if(!close.isEVal() && close && last_cmd != 2)last_cmd = 2, set = true;
  if(!stop.isEVal() && stop && last_cmd != 3)	last_cmd = 3, set = true;
  if(set && tCmd > 0) w_tm = tCmd;
  if(w_tm > 0) w_tm -= 1/f_frq;
  else {
  	w_tm = 0;
  	if(tCmd > 0) {
  		if(last_cmd == 1)	com = false;
  		if(last_cmd == 2)	close = false;
  		if(last_cmd == 3)	stop = false;
  		last_cmd = 0;
  	}
  }


ID: pidUnifImp
NAME: Impulse PID signal (unified, violation statuses)
uk#NAME: Імпульсний ПІД сигнал (уніфікований, стани порушень)
ru#NAME: ПИД импульсный сигнал (унифицированный, состояния нарушений)
DESCR:
  Common, representative and unified template of an interface to the Proportional Integral Differential (PID) regulator based on the common analog input signal but with the PWM-output, extended by binary states of indication the violations and mostly like to the template PID signal (unified, violation statuses). The template forms a structure of the impulse PID-regulator which can be easily connected to some cadres of the main elements library of the user interface just pointing the parameter object.

  The representative structure of the impulse PID-regulators is mostly equal to the template "PID signal (unified, violation statuses)" and contains a number of attributes specific to the pulse output and the attribute of determining the operation of this regulator in the analog mode, that is, this template is even more generalizable:
  - "Impulse output up (impQup)" and "Impulse output down (impQdwn)" — signals of the PWM-output.
  - "Mode: analog (analog)" — a sign of working the regulator in the analog output mode.

  Functions:
  Mostly the same as the basic template "PID signal (unified, violation statuses)" and the impulse-specific attributes are additionally provided: "Impulse output up", "Impulse output down", "Mode: analog", "T impulses period", "T minimal impulse", "Impulse rate factor".

  Author: Roman Savochenko <roman@oscada.org>
  Sponsored by: DIYA LTD
  Version: 1.1.0
  License: GPLv2

uk#DESCR:
  Загальний, представницький та уніфікований шаблон інтерфейсу до Пропорційного Інтегрального Диференційного (ПІД) регулятору заснованому на аналоговому вхідному сигналі але із ШІМ-виходом, розширеному бінарними станами індикації порушень та переважно схоже на шаблон ПІД сигнал (уніфікований, стани порушень). Шаблон формує структуру імпульсного ПІД-регулятору, який може бути легко підключений до деяких кадрів та віджетів бібліотеки основних елементів інтерфейсу користувача, просто вказавши об'єкт параметру.

  Представницька структура імпульсних ПІД-регуляторів переважно еквівалентна шаблону "ПІД сигнал (уніфікований, стани порушень)" та містить низку атрибутів, специфічних до імпульсного виходу та атрибут визначення роботи цього регулятору у аналоговому режимі, тобто цей шаблон є навіть більш узагальнювальним:
  - "Імпульсний вихід у гору (impQup)" та "Імпульсний вихід до низу (impQdwn)" — сигнали ШІМ-виходу.
  - "Режим: аналоговий (analog)" — ознака роботи регулятору у режимі аналогового виходу.

  Функції:
  Переважно те саме що у базового шаблону "ПІД сигнал (уніфікований, стани порушень)" та додатково надаються імпульсно-специфічні атрибути: "Імпульсний вихід у гору", "Імпульсний вихід до низу", "Режим: аналоговий", "T період імпульсів", "Мінімальна довжина імпульсу", "Рейтинг фактор імпульсів".

  Автор: Роман Савоченко <roman@oscada.org>
  Спонсоровано: ТОВ "ДІЯ"
  Версія: 1.1.0
  Ліцензія: GPLv2

PROGRAM:
  JavaLikeCalc.JavaScript
  if(f_start) {
  	f_err = "0";
  	alDelay_ = 0;
  }

  if(plcImit) {
  	if(!plcImitIn.isEVal()) in = plcImitIn;
  	else {
  		plcDif = plcMax-plcMin;
  		in = plcMin + plcDif/2 + rand(plcDif/10)-plcDif/20;
  	}
  }

  tErr = "0";
  if(in > (plcMax+plcExcess*(plcMax-plcMin)/100))
  { tErr = "1:"+tr("Signal exceed to upper hardware border"); var = max+plcExcess*(max-min)/100; }
  else if(in < (plcMin-plcExcess*(plcMax-plcMin)/100))
  { tErr = "2:"+tr("Signal exceed to bottom hardware border"); var = min-plcExcess*(max-min)/100; }
  if(tErr)	EVAL = true;
  else {
  	vCalibr = iMult*(in+iAdd);

  	vCalibr = (vCalibr-plcMin)/(plcMax-plcMin);
  	varDt = min + (max-min)*(scSqr?pow(vCalibr,0.5):vCalibr) - var;
  	var += varDt/max(1,Tf/1000*f_frq);

  	bndVarHyst = (aMax-aMin)*HystBnd/100;
  	if(aMax > aMin && (var >= aMax || (HH && var >= (aMax-bndVarHyst))))
  	{ tErr = "3:"+tr("Upper alarm border error"); HH = true; EVAL = H = LL = L = false; }
  	else if(aMax > aMin && (var <= aMin || (LL && var <= (aMin+bndVarHyst))))
  	{ tErr="4:"+tr("Lower alarm border error"); LL = true; EVAL = HH = H = L = false; }
  	else if(wMax > wMin && (var >= wMax || (H && var >= (wMax-bndVarHyst))))
  	{ tErr="5:"+tr("Upper warning border error"); H = true; EVAL = HH = LL = L = false; }
  	else if(wMax > wMin && (var <= wMin || (L && var <= (wMin+bndVarHyst))))
  	{ tErr="6:"+tr("Lower warning border error"); L = true; EVAL = HH = H = LL = false; }
  	else if(speed && varDt > speed)
  	{ tErr = "7:"+tr("Too big parameter's motion speed"); EVAL = true; HH = H = LL = L = false; }
  	else EVAL = HH = H = LL = L = false;
  }

  //Alarms forming
  if(alSup) {
  	if(f_err.toInt())	this.alarmSet(DESCR+": "+tr("SUPPRESSED"), 1);
  	f_err = "0";
  }
  else {
  	if(tErr.toInt() && tErr.toInt() != f_err.toInt() && this.cntr().status().toInt())	return;
  	if(alDelay > 0 && alDelay_ <= 0 && tErr.toInt() != f_err.toInt())	tErr1 = tErr.toInt();
  	if(alDelay > 0 && alDelay_ > 0 && tErr.toInt() != tErr1)	{ alDelay_ = 0; tErr1 = tErr.toInt(); }
  	if(alDelay > 0 && alDelay_ < alDelay){ alDelay_ += 1/f_frq; return; }
  	if(tErr.toInt())	this.alarmSet(DESCR+": "+tErr.parse(1,":"), -4);
  	else	this.alarmSet(DESCR+": "+tr("NORMA"), 1);
  	f_err = tErr;
  	alDelay_ = 0;
  }


ID: anUnifSt
NAME: Analog signal (unified, violation statuses)
uk#NAME: Аналог. сигнал (уніфікований, стани порушень)
ru#NAME: Аналог. сигн. (унифицированный, состояния нарушений)
DESCR:
  Common, representative and unified template of analog input signals processing, extended by binary states of indication the violations. The template grounded on the base template "Analog signal (unified)" with its representative structure and some differences characteristic to independent development and expansion.
  Binary states were provided for the convenient use of algorithms of operation at the borders of violations of the parameter object, preferably in the block diagrams of general control algorithms.

  Functions:
  Mostly the same as the basic "Analog signal (unified)" and the borderline signs are additionally provided: "H", "L", "HH", "LL", "EVAL".

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

uk#DESCR:
  Загальний, представницький та уніфікований шаблон обробки аналогових вхідних сигналів, розширений бінарними станами індикації порушень. Шаблон засновано на базовому шаблоні "Аналоговий сигнал (уніфікований)" з відповідною до нього представницькою структурою та деякими відмінностями, характерними до незалежного розвитку та розширення.
  Бінарні стани передбачалося для зручного використання у алгоритмах роботи за границями порушення об'єкту параметру, переважно у блокових схемах загальних алгоритмів керування.

  Функції:
  Переважно відповідають базовому шаблону "Аналоговий сигнал (уніфікований)" та додатково надаються ознаки порушень границь: "H", "L", "HH", "LL", "EVAL".

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

ru#DESCR:
  Унифицированный шаблон обработки аналогового входного сигнала.

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

PROGRAM:
  JavaLikeCalc.JavaScript
  if(f_start) {
  	prevVar = EVAL_REAL;
  	alDelay_ = 0;
  	//Prepare data for preprocessing
  	inPrcId = this.nodePath("_");
  	inPrcLng = "JavaLikeCalc.JavaScript";
  	inPrcArgs = new Object();
  	inPrcArgs.this = this;
  	inPrcArgs.ctx = new Object();
  	return;
  }
  if(f_stop) return;

  pMax = plcMax; pMin = plcMin;	//Copy for local modifies using
  if(passIn=(pMax==pMin)) { pMax = max/iMult - iAdd; pMin = min/iMult - iAdd; }

  if(plcImit) {	//Data imitation
  	if(!plcImitIn.isEVal()) in = plcImitIn;
  	else {
  		var plcOff;
  		plcDif = abs(pMax-pMin);
  		if(plcOff.isEVal())	plcOff = rand(plcDif/2);
  		in = pMin + plcDif/4 + plcOff + rand(plcDif/10)-plcDif/20;
  	}
  }

  //Call specific preprocessing procedure
  if(inProc.length)	{
  	inPrcArgs.f_frq = f_frq;
  	inPrcArgs.in = in; inPrcArgs.var = var; inPrcArgs.min = min; inPrcArgs.max = max;
  	inPrcArgs.plcMin = pMin; inPrcArgs.plcMax = pMax;
  	inPrcArgs.plcImit = plcImit; inPrcArgs.plcImitIn = plcImitIn;
  	SYS.DAQ.funcCall(inPrcLng, inPrcArgs, inProc, inPrcId);
  	in = inPrcArgs.in;
  }

  levErr = 0;
  tErr = "0";
  //Input data check and postprocess
  if(in.isEVal()) {
  	tErr = "1:"+tr("No data or connection with source"); levErr = -5;
  	var = EVAL_REAL;
  	if(subMode == 1) var = prevVar;
  	else if(subMode == 2) var = subVar;
  }
  else if(in > (max(pMax,pMin)+plcExcess*abs(pMax-pMin)/100)) {
  	tErr = "1:"+tr("The signal exceed to upper hardware border"); levErr = -5;
  	var = EVAL_REAL;
  	if(subMode == 1) var = prevVar.isEVal() ? max+plcExcess*(max-min)/100 : prevVar;
  	else if(subMode == 2) var = subVar;
  }
  else if(in < (min(pMax,pMin)-plcExcess*abs(pMax-pMin)/100)) {
  	tErr = "2:"+tr("The signal exceed to bottom hardware border"); levErr = -5;
  	var = EVAL_REAL;
  	if(subMode == 1) var = prevVar.isEVal() ? min-plcExcess*(max-min)/100 : prevVar;
  	else if(subMode == 2) var = subVar;
  }
  if(tErr)	EVAL = true, HH = H = LL = L = false;
  else {
  	vCalibr = iMult*(in+iAdd);
  	if(passIn) { pMin = iMult*(pMin+iAdd); pMax = iMult*(pMax+iAdd); }
  	if(!passIn || scSqr) {
  		vCalibr = (vCalibr-min(pMax,pMin))/abs(pMax-pMin);
  		if(pMax < pMin) vCalibr = 1-vCalibr;
  		vCalibr = min + (max-min)*(scSqr?pow(vCalibr,0.5):vCalibr);
  	}
  	if(var.isEVal())	var = vCalibr;
  	varDt = vCalibr - var;
  	var += varDt/max(1,Tf*f_frq);
  	prevVar = var;

  	bndVarHyst = (max-min)*HystBnd/100;
  	EVAL = HH_ = H_ = LL_ = L_ = false;
  	if(speed && varDt > speed)	{ tErr = "7:"+tr("Too big parameter's motion speed"); levErr = -2; }
  	if(wMin > min && wMax > wMin && (var <= wMin || (L && var <= (wMin+bndVarHyst))))
  	{ tErr = "6:"+tr("Lower warning border error"); levErr = -2; L_ = true; }
  	if(wMax < max && wMax > wMin && (var >= wMax || (H && var >= (wMax-bndVarHyst))))
  	{ tErr = "5:"+tr("Upper warning border error"); levErr = -2; H_ = true; }
  	if(aMin > min && aMax > aMin && (var <= aMin || (LL && var <= (aMin+bndVarHyst))))
  	{ tErr = "4:"+tr("Lower alarm border error"); levErr = -4; LL_ = true; }
  	if(aMax < max && aMax > aMin && (var >= aMax || (HH && var >= (aMax-bndVarHyst))))
  	{ tErr = "3:"+tr("Upper alarm border error"); levErr = -4; HH_ = true; }
  	HH = HH_; H = H_; LL = LL_; L = L_;
  }

  //Alarms forming
  if(alSup) {
  	if(f_err.toInt())	this.alarmSet(DESCR+": "+tr("SUPPRESSED"), 1);
  	f_err = "0";
  }
  else {
  	if(tErr.toInt() && tErr.toInt() != f_err.toInt() && this.cntr().status().toInt())	return;
  	if(alDelay > 0 && alDelay_ <= 0 && tErr.toInt() != f_err.toInt())	tErr1 = tErr.toInt();
  	if(alDelay > 0 && alDelay_ > 0 && tErr.toInt() != tErr1)	{ alDelay_ = 0; tErr1 = tErr.toInt(); }
  	if(alDelay > 0 && alDelay_ < alDelay){ alDelay_ += 1/f_frq; return; }
  	if(tErr.toInt())	this.alarmSet(DESCR+": "+tErr.parse(1,":"), levErr);
  	else	this.alarmSet(DESCR+": "+tr("NORMA"), 1);
  	f_err = tErr;
  	alDelay_ = 0;
  }


ID: pidUnif
NAME: PID signal (unified, violation statuses)
uk#NAME: ПІД сигнал (уніфікований, стани порушень)
ru#NAME: ПИД сигнал (унифицированный, состояния нарушений)
DESCR:
  Common, representative and unified template of an interface to the Proportional Integral Differential (PID) regulator based on the common analog input signal, extended by binary states of indication the violations. The template forms a structure of the analog PID-regulator which can be easily connected to some cadres and widgets of the main elements library of the user interface just pointing the parameter object.

  The representative structure of the analog PID-regulators is:
  - "Variable (var)" — end variable of the parameter — engineeric real value, allowed and suitable for archiving.
  - "Error (err)" — obligatory attribute of any parameter, consist of the combination of the error code and short text description, like to "2:No data or connection with source". The template reserves next error codes:
    - 1, 2 — hardware errors, when the data mostly wrong;
    - 3, 4 — alarm border errors;
    - 5, 6 — warning border errors;
    - 7 — the speed error of the variable changing.
  - "Violations suppress (alSup) and delay (alDelay)" — violations generic control for suppressing and delaying.
  - "Setpoint (sp)" — setpoint for the analog signal value achievement in the automatic mode.
  - "Manual input (manIn)" — attribute for entering a new output value, which in the next falls into the output at the manual mode.
  - "Output (out)" — output (control signal) of the PID-regulator.
  - "Mode: automate (auto)" — the PID-regulator mode "Automatic".
  - "Mode: cascade (casc)" — the PID-regulator mode "Cascade".
  - "Scale: minimum (min)" and "Scale: maximum (max)" — main scale of the end variable, the output of which causes a hardware border error. The scale is also used as a scale of the variable trend display on the graphs.
  - "Logarithmic scale (log)" — the scale sign of the variable trend display on the graphs in the logarithmic scale.
  - "Dimension (ed)" — dimension (unit of measurement) of the variable.
  - "Precision (prec)" — number signs after the dot, for positive values, and precision (signs in whole), for negative ones, to display the real end variable on the screen.

  Functions:
  - Generic processing of the raw analog input for:
    - simple correction-calibration at the formula "in = iMult*(in+iAdd)";
    - scaling from the hardware border [plcMin...plcMax] to the main border [min...max], applying the square scale scSqr;
    - permission to exceed the border for the input value on the value of plcExcess percent;
    - filtering the input value changing in the time Tf.
  - Processing the result variable var for violation some borders and criteria, generating the alarms and proper setting the attribute err. The alarm borders can have some hysteresis HystBnd and can be suppressed setting alSup. Next borders and criteria are provided:
  - missing for data or connection with source at the EVAL input value — error code 1 and alarm level 5;
  - exceeding the input value of the hardware border — error code 1,2 and alarm level 5;
  - exceeding the end variable of the alarm border [aMin...aMax] — error code 3,4 and alarm level 4;
    !!! Disabled at setting for equal or inverted values of the border
  - exceeding the end variable of the warning border [wMin...wMax] — error code 5,6 and alarm level 2;
    !!! Disabled at setting for equal or inverted values of the border
  big motion speed of the end variable — error code 7 and alarm level 2.
  - Transmission of the PID-specific information, control and coefficient attributes to and from the PLC or other data source with the regulation.

  Author: Roman Savochenko <roman@oscada.org>
  Sponsored by: DIYA LTD
  Version: 1.2.0
  License: GPLv2

uk#DESCR:
  Загальний, представницький та уніфікований шаблон інтерфейсу до Пропорційного Інтегрального Диференційного (ПІД) регулятору заснованому на аналоговому вхідному сигналі, розширеному бінарними станами індикації порушень. Шаблон формує структуру аналогового ПІД-регулятору, який може бути легко підключений до деяких кадрів та віджетів бібліотеки основних елементів інтерфейсу користувача, просто вказавши об'єкт параметру.

  Представницькою структурою аналогового ПІД-регулятору є:
  - "Змінна (var)" — кінцева змінна параметру — інженерне реальне значення, доступне та придатне до архівації.
  - "Помилка (err)" — обов'язковий атрибут будь якого параметру, що містить комбінацію коду помилки та короткого опису, на кшталт "2:Немає даних або підключення до джерела". Шаблон резервує наступні коди помилок:
    - 1, 2 — помилки обладнання, коли дані переважно помилкові;
    - 3, 4 — помилки аварійної границі;
    - 5, 6 — помилки попереджувальної границі;
    - 7 — помилка швидкості зміни змінної.
  - "Придушення (alSup) та затримка (alDelay) порушень" — загальний контроль порушень щодо придушення та затримки.
  - "Завдання (sp)" — завдання для досягнення значенням аналоговим сигналом у автоматичному режимі.
  - "Ручний ввід (manIn)" — атрибут введення нового значення виходу, яке надалі потрапляє до виходу у ручному режимі.
  - "Вихід (out)" — вихід (сигнал контролю) ПІД-регулятору.
  - "Режим: автомат (auto)" — режим "Автомат" ПІД-регулятору.
  - "Режим: каскад (casc)" — режим "Каскад" ПІД-регулятору.
  - "Шкала: мінімум (min)" та "Шкала: максимум (max)" — головна шкала кінцевої змінної, вихід за яку призводить до помилки апаратної границі. Шкала також використовується як шкала відображення тренду змінної на графіках.
  - "Логарифмічна шкала (log)" — ознака відображення тренду змінної на графіках у логарифмічній шкалі.
  - "Одиниця виміру (ed)" — одиниця виміру змінної.
  - "Точність (prec)" — кількість знаків після крапки, для позитивних значень, та точність (знаків загалом), для негативних, для відображення реальної кінцевої змінної на екрані.

  Функції:
  - Загальне опрацювання аналогового входу щодо:
    - проста корекція-калібрування за формулою "in = iMult*(in+iAdd)";
    - масштабування від апаратної границі [plcMin...plcMax] у головну границю [min...max], враховуючи квадратичну шкалу scSqr;
    - дозвіл на перевищення границі вхідним значенням на величину plcExcess відсотків;
    - фільтрування зміни вхідного значення на час Tf.
  - Проста імітація аналогового входу, встановленням plcImit та підключенням джерела імітації-симуляції до plcImitIn.
  - Опрацювання кінцевої змінної var на предмет порушення деяких границь та критеріїв, генеруючи аварії та відповідно встановлюючи атрибут err. Границі аварії можуть мати деякий гістерезис HystBnd, можуть бути затримані на час alDelay та можуть бути придушені встановленням alSup. Надаються наступні границі та критерії:
    - відсутність даних або підключення до джерела за вхідним значенням EVAL — код помилки 1 та рівень аварії 5;
    - перевищення апаратної границі вхідним значенням — код помилки 1,2 та рівень аварії 5;
    - перевищення аварійної границі кінцевою змінною [aMin...aMax] — код помилки 3,4 та рівень аварії 4;
  ￼ !!! Вимикається встановленням однакових або інверсних значень границі
    - перевищення попереджувальної границі кінцевою змінною [wMin...wMax] — код помилки 5,6 та рівень аварії 2;
  ￼ !!! Вимикається встановленням однакових або інверсних значень границі
    - велика швидкість зміни speed кінцевої змінної — код помилки 7 та рівень аварії 2.
  - Передавання специфічної ПІД інформації, контролю та атрибутів коефіцієнтів до та з ПЛК або іншого джерела даних із регулюванням.

  Автор: Роман Савоченко <roman@oscada.org>
  Спонсоровано: ТОВ "ДІЯ"
  Версія: 1.2.0
  Ліцензія: GPLv2

PROGRAM:
  JavaLikeCalc.JavaScript
  if(f_start) {
  	f_err = "0";
  	alDelay_ = 0;
  }

  if(plcImit) {
  	if(!plcImitIn.isEVal()) in = plcImitIn;
  	else {
  		plcDif = plcMax-plcMin;
  		in = plcMin + plcDif/2 + rand(plcDif/10)-plcDif/20;
  	}
  }

  tErr = "0";
  if(in > (plcMax+plcExcess*(plcMax-plcMin)/100))
  { tErr = "1:"+tr("Signal exceed to upper hardware border"); var = max+plcExcess*(max-min)/100; }
  else if(in < (plcMin-plcExcess*(plcMax-plcMin)/100))
  { tErr = "2:"+tr("Signal exceed to bottom hardware border"); var = min-plcExcess*(max-min)/100; }
  if(tErr)	EVAL = true;
  else {
  	vCalibr = iMult*(in+iAdd);

  	vCalibr = (vCalibr-plcMin)/(plcMax-plcMin);
  	varDt = min + (max-min)*(scSqr?pow(vCalibr,0.5):vCalibr) - var;
  	var += varDt/max(1,Tf/1000*f_frq);

  	bndVarHyst = (aMax-aMin)*HystBnd/100;
  	if(aMax > aMin && (var >= aMax || (HH && var >= (aMax-bndVarHyst))))
  	{ tErr = "3:"+tr("Upper alarm border error"); HH = true; EVAL = H = LL = L = false; }
  	else if(aMax > aMin && (var <= aMin || (LL && var <= (aMin+bndVarHyst))))
  	{ tErr="4:"+tr("Lower alarm border error"); LL = true; EVAL = HH = H = L = false; }
  	else if(wMax > wMin && (var >= wMax || (H && var >= (wMax-bndVarHyst))))
  	{ tErr="5:"+tr("Upper warning border error"); H = true; EVAL = HH = LL = L = false; }
  	else if(wMax > wMin && (var <= wMin || (L && var <= (wMin+bndVarHyst))))
  	{ tErr="6:"+tr("Lower warning border error"); L = true; EVAL = HH = H = LL = false; }
  	else if(speed && varDt > speed)
  	{ tErr = "7:"+tr("Too big parameter's motion speed"); EVAL = true; HH = H = LL = L = false; }
  	else EVAL = HH = H = LL = L = false;
  }

  //Alarms forming
  if(alSup) {
  	if(f_err.toInt())	this.alarmSet(DESCR+": "+tr("SUPPRESSED"), 1);
  	f_err = "0";
  }
  else {
  	if(tErr.toInt() && tErr.toInt() != f_err.toInt() && this.cntr().status().toInt())	return;
  	if(alDelay > 0 && alDelay_ <= 0 && tErr.toInt() != f_err.toInt())	tErr1 = tErr.toInt();
  	if(alDelay > 0 && alDelay_ > 0 && tErr.toInt() != tErr1)	{ alDelay_ = 0; tErr1 = tErr.toInt(); }
  	if(alDelay > 0 && alDelay_ < alDelay){ alDelay_ += 1/f_frq; return; }
  	if(tErr.toInt())	this.alarmSet(DESCR+": "+tErr.parse(1,":"), -4);
  	else	this.alarmSet(DESCR+": "+tr("NORMA"), 1);
  	f_err = tErr;
  	alDelay_ = 0;
  }


ID: SNMP
NAME: Network devices by SNMP
uk#NAME: Мережеві пристрої за SNMP
ru#NAME: Сетевые устройства по SNMP
DESCR:
  Data combination of a device, accessible by the protocol SNMP, in a complex object of the attribute "All items". The template designed to use together with the DAQ-module "SNMP" and to represent this data by the frame "Object properties" as a complex object with properties, signalling at single borders and writing. Considering the great specificity and variety of SNMP-accessible devices, this template is actually a billet and an example of creating a template based on it to a corresponding device with a specific to it processing of input properties, forming of violations and write capability.

  Author: Roman Savochenko <roman@oscada.org>
  Sponsored by: PAC HARTRON
  Version: 1.1.0
  License: GPLv2

uk#DESCR:
  Об'єднання даних пристрою, доступного за протоколом SNMP, у комплексному об'єкті атрибуту "Всі елементи". Шаблон розроблено для використання із модулем джерела даних "SNMP" та представлення цих даних кадром "Властивості об'єкту" як комплексний об'єкт із властивостями, сигналізацією за окремими границями та записом. Враховуючи велику специфіку та розмаїття пристроїв доступних за протоколом SNMP, цей шаблон фактично є заготовкою та прикладом створення на його основі шаблону до відповідного пристрою із специфічною до нього обробкою вхідних властивостей, формування порушень та можливістю запису.

  Автор: Роман Савоченко <roman@oscada.org>
  Спонсорування: ПАС ХАРТРОН
  Версія: 1.1.0
  Ліцензія: GPLv2

PROGRAM:
  JavaLikeCalc.JavaScript
  if(f_start)	{ srcPrm = false; items = new Object(); alDelay_ = 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_");
  	lstTable = "";
  	for(i_n = 0; i_n < nLst.length; i_n++) {
  		aNd = srcPrm[nLst[i_n]];
  		aId = nLst[i_n].slice(2);
  		aIdPrc = aNd.descr();
  		if(!aIdPrc.parse(1,"::").length) continue;
  		if(aIdPrc.slice(-13) == "TotalNumber.0")	{ lstTable = aIdPrc.slice(0,-13); continue; }

  		//Manual tables check
  		if(!lstTable.length || lstTable != aIdPrc.slice(0,lstTable.length))
  			for(off = 0; (iMnT=manTables.parse(0,";",off)).length; )
  				if(iMnT == aIdPrc.slice(0,iMnT.length)) { lstTable = iMnT; break; }
  		
  		if(lstTable.length && lstTable == aIdPrc.slice(0,lstTable.length))
  			aIdPrc = lstTable.parse(1,"::")+(prt1=aIdPrc.slice(lstTable.length)).parse(1,".")+prt1.parse(0,".");
  		else aIdPrc = aIdPrc.parse(1,"::").parse(0,".");

  		if(items[aIdPrc].isEVal()) {
  			items[aIdPrc] = itW = new Object();
  			itW.descr = aIdPrc;//aNd.descr();
  			itW.id = aId;

  			// 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;
  		}
  		cVl = aNd.get();
  		// Selectable value specifying
  		if(aNd.flg()&0x01)
  			for(off = 0, pos = 0; (selId=aNd.values().parse(0,";",off)).length; pos++)
  				if(cVl == selId && cVl != aNd.selNames().parse(pos,";")) {		
  					cVl = aNd.selNames().parse(pos,";")+"("+cVl+")";
  					break;
  				}
  		items[aIdPrc].val = cVl;
  	}

  	//Alarms process and mark
  	/*varS = "battery_packs";
  	if(tP=srcPrm[varS])
  	{
  		if(tP.get().toInt() == 0)	{ items[varS].alarm = 2; tErr += "None good battery present; "; }
  		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(alSup) {
  	if(f_err.toInt())	this.alarmSet(DESCR+": "+tr("SUPPRESSED"), 1);
  	f_err = "0";
  }
  else {
  	if(tErr.toInt() && tErr.toInt() != f_err.toInt() && this.cntr().status().toInt())	return;
  	if(alDelay > 0 && alDelay_ <= 0 && tErr.toInt() != f_err.toInt())	tErr1 = tErr.toInt();
  	if(alDelay > 0 && alDelay_ > 0 && tErr.toInt() != tErr1)	{ alDelay_ = 0; tErr1 = tErr.toInt(); }
  	if(alDelay > 0 && alDelay_ < alDelay){ alDelay_ += 1/f_frq; return; }
  	if(tErr.toInt())	this.alarmSet(DESCR+": "+tErr.parse(1,":"), -(2+alLev));
  	else	this.alarmSet(DESCR+": "+tr("NORMA"), 1);
  	f_err = tErr;
  	alDelay_ = 0;
  }


ID: codeState
NAME: Code state
uk#NAME: Стан за кодом
ru#NAME: Состояние по коду
ru#DESCR:
  Формирование состояния по коду

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

DESCR:
  A variant of the common, representative and unified template of the block for union of Discrete parameters, expanded by more than two states and three commands that can be encoded by an integer value.
  The template forms a structure of parameter (complex tag) which can be easily connected to most widgets and cadres of the main elements library of the user interface just pointing the parameter object.

  Functions:
  - Direct receiving, by link, the status code and the command (read only), as well as setting the status text according to the list of states stats.
  - Working out the text of the command com_text to find it in the general list coms of commands and issuing the received command code to the output.
  - Generating from the general list coms of commands the list of commands to be selected in digComs.
  - Complex processing and complete generation-imitation of the code state, as well as processing the code or the command text for targeted actions, on the internal programming language of OpenSCADA into the configuration IO inProc, where you can operate next service parameters:
    - in [IN|OUT] — IO of the code state;
    - text [OUT] — direct text status setting;
    - coms [IN] — list of available commands, of the corresponded IO;
    - com_text [IN|OUT] — text of the received command;
    - levErr, tErr [IN|OUT] — alarm level [-7...0] and text of the error (the attribute "err" format);
    - f_frq [IN] — frequency of the calculation, the template IO;
    - this [IN] — reference to the parameter object, what executing the template;
    - ctx [IN] — object of the user context, what saved between the execution cycles.
  - Formation of the violation and the corresponding setting of the attribute err, provided at setting in the processing procedure or lack of the communication (in = EVAL).

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

uk#DESCR:
  Варіант загального, представницького та уніфікованого шаблону блоку поєднання дискретних параметрів, розширений більш ніж двома станами та трьома командами які можна закодувати цілим значенням.
  Шаблон формує структуру параметру (складного тегу) стану за кодом який може бути легко підключений до більшості віджетів та кадрів бібліотеки основних елементів інтерфейсу користувача просто вказавши об'єкт параметру.

  Функції:
  - Пряме отримання, за посиланням, коду стану та команди (тільки читання), а також встановлення тексту стану згідно до переліку станів stats.
  - Опрацювання тексту команди com_text на предмет пошуку її у загальному переліку команд coms та видача отриманого коду команди на вихід.
  - Формування із загальному переліку команд coms переліку команд для обрання у digComs.
  - Складна обробка та повна генерація-імітація коду стану, а також обробка коду або тексту команди для цільових дій, на внутрішній мові програмування OpenSCADA у конфігураційному ВВ inProc, де Ви можете оперувати наступними сервісними параметрами:
    - in [IN|OUT] — ВВ коду статусу;
    - text [OUT] — пряме встановлення тексту статусу;
    - coms [IN] — перелік наявних команд, відповідного ВВ;
    - com_text [IN|OUT] — текст отриманої команди;
    - levErr, tErr [IN|OUT] — рівень аварії [-7...0] та текст помилки (формат атрибуту "err");
    - f_frq [IN] — частота обчислення, шаблонний ВВ;
    - this [IN] — посилання на об'єкт параметру, що виконує шаблон;
    - ctx [IN] — об'єкт користувацького контексту, що зберігається між циклами виклику.
  - Формування порушення та відповідне встановлення атрибуту err, за умови встановлення у процедурі обробки або відсутності зв'язку (in = EVAL).

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

PROGRAM:
  JavaLikeCalc.JavaScript
  if(f_start) {
  	f_err = "0";
  	alDelay_ = 0;
  	//Prepare data for preprocessing
  	inPrcId = this.nodePath("_");
  	inPrcLng = "JavaLikeCalc.JavaScript";
  	inPrcArgs = new Object();
  	inPrcArgs.this = this;
  	inPrcArgs.ctx = new Object();
  	return;
  }
  if(f_stop) return;

  tErr = "0", levErr = 0;

  //Call a specific preprocessing procedure
  st_text = "";
  if(inProc.length)	{
  	inPrcArgs.f_frq = f_frq;
  	inPrcArgs.in = in;
  	inPrcArgs.text = "";
  	inPrcArgs.levErr = levErr; inPrcArgs.tErr = tErr;
  	inPrcArgs.coms = coms; inPrcArgs.com_text = com_text;
  	SYS.DAQ.funcCall(inPrcLng, inPrcArgs, inProc, inPrcId);
  	in = inPrcArgs.in;
  	levErr = inPrcArgs.levErr; tErr = inPrcArgs.tErr;
  	st_text = inPrcArgs.text;
  	com_text = inPrcArgs.com_text;
  }

  //Commands processing
  digComs = "";
  if(!coms.length)	com_text = EVAL;
  else if(com_text.isEVal())	com_text = "";
  for(off = 0; (tVl=coms.parseLine(0,off)).length; ) {
  	off1 = 0;
  	code = tVl.parse(0,":",off1).toInt();
  	st = tVl.slice(off1);
  	digComs += (digComs.length?"\n":"") + st;
  	if(com_text.length && com_text == st)	out = code;
  }
  if(!com_text.isEVal()) com_text = "";

  //State set
  if(st_text.length) ;
  else if(in.isEVal()) {
  	tErr = "1:"+tr("No data or connection with source");
  	levErr = -5;
  	st_text = tr("No data");
  }
  else {
  	st_text = tr("Unknown")+" "+in;
  	for(off = 0; (tVl=stats.parseLine(0,off)).length; ) {
  		off1 = 0;
  		if(in == tVl.parse(0,":",off1).toInt())	{ st_text = tVl.slice(off1); break; }
  	}
  }

  //Alarms forming
  if(alSup) {
  	if(f_err.toInt())	this.alarmSet(DESCR+": "+tr("SUPPRESSED"), 1);
  	f_err = "0";
  }
  else {
  	if(tErr.toInt() && tErr.toInt() != f_err.toInt() && this.cntr().status().toInt())	return;
  	if(alDelay > 0 && alDelay_ <= 0 && tErr.toInt() != f_err.toInt())	tErr1 = tErr.toInt();
  	if(alDelay > 0 && alDelay_ > 0 && tErr.toInt() != tErr1)	{ alDelay_ = 0; tErr1 = tErr.toInt(); }
  	if(alDelay > 0 && alDelay_ < alDelay){ alDelay_ += 1/f_frq; return; }
  	if(tErr.toInt())	this.alarmSet(DESCR+": "+tErr.parse(1,":"), levErr);
  	else	this.alarmSet(DESCR+": "+tr("NORMA"), 1);
  	f_err = tErr;
  	alDelay_ = 0;
  }


ID: ntf
NAME: Notificator by SMS, EMail(SMTP)
uk#NAME: Повідомлювач за SMS, EMail(SMTP)
ru#NAME: Уведомитель посредством SMS, EMail(SMTP)
DESCR:
  The complex template of the notification contains of parts of the dispatcher and the output user protocol of notification by EMail(SMTP) and SMS.

  THE DISPATCHER can be performed for pointed messages of the message buffer of OpenSCADA and applied on the Logical level or the controller object of the module JavaLikeCalc.

  THE OUTPUT USER PROTOCOL PART "SMS" provides operations with SMS by a GSM-modem connected as serial device. For now, there supported only sending SMS messages to a number of remote cell phone or GSM-modem. For sending there are supported: ECHO disable, PIN check and set, sending in PDU and the Text mode.

  THE OUTPUT USER PROTOCOL PART "SMTP" provides operations with a SMTP-server for delivering EMails by their sending through TCP-Socket or SSL. For now, there are supported: TCP, SSL, AUTH, topic encoding for UTF-8.

  Author: Roman Savochenko <roman@oscada.org>
  Sponsored by: SVItoVYR LTD
  Version: 1.0.0
  License: GPLv2

uk#DESCR:
  Комплексний шаблон повідомлення містить частини диспетчеру та вихідний користувацький протокол повідомлення за EMail(SMTP) та SMS.

  ДИСПЕТЧЕР може виконуватися для вказаних повідомлень буферу повідомлень OpenSCADA та застосовується на Логічному рівні або об'єкті контролеру модуля JavaLikeCalc.

  "SMS" ЧАСТИНА ВИХІДНОГО КОРИСТУВАЦЬКОГО ПРОТОКОЛУ надає операції із SMS за допомогою GSM-модему, підключеного як послідовний пристрій. Наразі підтримується лише відправка SMS повідомлень на номер віддаленого мобільного телефону або GSM-модему. Для надсилання підтримується: вимкнення ЛУНИ, перевірка та встановлення PIN, надсилання у PDU та текстовому режимі.

  "SMTP" ЧАСТИНА ВИХІДНОГО КОРИСТУВАЦЬКОГО ПРОТОКОЛУ надає операції із SMTP-сервером щодо доставки електронної пошти відправленням через TCP-Сокет або SSL. Наразі підтримуються: TCP, SSL, AUTH, кодування теми у UTF-8.

  Автор: Роман Савоченко <roman@oscada.org>
  Спонсоровано: ТОВ "СВІТоВИР АВТоМАТИК"
  Версія: 1.0.0
  Ліцензія: GPLv2

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

  //-----------------------------------------------
  //Request form of the UserProtocol ProtIt="SMTP":
  //-----------------------------------------------
  //<send auth="{user}:{pass}" from="{FromAddr}" to="{ToAddr}" topic="{My Topic}" err="1:Error">{MessageText}</send>
  //  topic - topic of the message;
  //  from - sender address;
  //  to - destination address of the receiver;
  //  auth - authenticate user and password;
  //  MessageText - text of the message;
  //  err - sets for the request result.
  function SMTP( ) {
  	//Transport's timings check
  	if(tr.timings() != "5:1")	tr.timings("5:1");
  	io.setAttr("err", "");
  	if(!tr.start(true))	{ io.setAttr("err", "10:"+tr("Impossible connect to the SMTP-server.")); return; }

  	//Wait for a greeting after the connection
  	rez = "";
  	for(iTr = 0; iTr < 5 && !rez.length; iTr++) rez += tr.messIO("");
  	while(rez.length && rez.slice(-2) != "\x0D\x0A" && (trez=tr.messIO("")).length) rez += trez;

  	auth = io.attr("auth");

  	//Send HELLO
  	rez = tr.messIO("EHLO "+SYS.system("hostname -f").parse(0,"\n")+"\x0D\x0A");
  	while(rez.length && rez.slice(-2) != "\x0D\x0A" && (trez=tr.messIO("")).length) rez += trez;
  	if(!rez.length)	{ io.setAttr("err", "100:"+tr("No response.")); return; }
  	for(off = 0; (sit=rez.parse(0,"\x0D\x0A",off)).length; )
  		if(sit.toInt() != 250)	{ io.setAttr("err", "101:"+tr("Error HELLO: %1.").replace("%1",sit)); return; }
  		else if(sit.indexOf("AUTH LOGIN") >= 0) {
  			if(sit.indexOf("PLAIN") < 0)	{ io.setAttr("err", "101:"+tr("Unsupported auth methods: %1.").replace("%1",sit)); return; }
  			else if(!auth.length)			{ io.setAttr("err", "101:"+tr("Auth required: %1.").replace("%1",sit)); return; }
  		}

  	//Send AUTH
  	if(auth.length) {
  		rez = tr.messIO("AUTH LOGIN\x0D\x0A");
  		while(rez.length && rez.slice(-2) != "\x0D\x0A" && (trez=tr.messIO("")).length) rez += trez;
  		if(!rez.length)	{ io.setAttr("err", "100:"+tr("No response.")); return; }
  		if(rez.toInt() != 334)	{ io.setAttr("err", "102:"+tr("AUTH error: %1.").replace("%1",rez)); return; }

  		rez = tr.messIO(SYS.strEncode(io.attr("auth").parse(0,":"),"Base64")+"\x0D\x0A");
  		while(rez.length && rez.slice(-2) != "\x0D\x0A" && (trez=tr.messIO("")).length) rez += trez;
  		if(!rez.length)	{ io.setAttr("err", "100:"+tr("No response.")); return; }
  		if(rez.toInt() != 334)	{ io.setAttr("err", "102:"+tr("AUTH USER error: %1.").replace("%1",rez)); return; }

  		rez = tr.messIO(SYS.strEncode(io.attr("auth").parse(1,":"),"Base64")+"\x0D\x0A");
  		while(rez.length && rez.slice(-2) != "\x0D\x0A" && (trez=tr.messIO("")).length) rez += trez;
  		if(!rez.length)	{ io.setAttr("err", "100:"+tr("No response.")); return; }
  		if(rez.toInt() != 235)	{ io.setAttr("err", "102:"+tr("AUTH PASS error: %1.").replace("%1",rez)); return; }
  	}

  	//Send FROM
  	rez = tr.messIO("MAIL FROM:<"+io.attr("from")+">\x0D\x0A");
  	while(rez.length && rez.slice(-2) != "\x0D\x0A" && (trez=tr.messIO("")).length) rez += trez;
  	if(!rez.length)	{ io.setAttr("err", "100:"+tr("No response.")); return; }
  	if(rez.toInt() != 250)	{ io.setAttr("err", "103:"+tr("MAIL FROM error: %1.").replace("%1",rez)); return; }

  	//Send TO
  	rez = tr.messIO("RCPT TO:<"+io.attr("to")+">\x0D\x0A");
  	while(rez.length && rez.slice(-2) != "\x0D\x0A" && (trez=tr.messIO("")).length) rez += trez;
  	if(!rez.length)	{ io.setAttr("err", "100:"+tr("No response.")); return; }
  	if(rez.toInt() != 250)	{ io.setAttr("err", "104:"+tr("RCPT TO error: %1.").replace("%1",rez)); return; }

  	//Prepare and send DATA
  	rez = tr.messIO("DATA\x0D\x0A");
  	while(rez.length && rez.slice(-2) != "\x0D\x0A" && (trez=tr.messIO("")).length) rez += trez;
  	if(!rez.length)	{ io.setAttr("err", "100:"+tr("No response.")); return; }
  	if(rez.toInt() != 354)	{ io.setAttr("err", "105:"+tr("DATA error: %1.").replace("%1",rez)); return; }

  	// Req version
  	reqVer = SYS.XMLNode("get").setAttr("path","/%2fgen%2fver"); SYS.cntrReq(reqVer);

  	data = "Message-ID: <"+rand(999999).toString()+"."+rand(999999999).toString()+"-OpenSCADA@"+SYS.system("hostname").parse(0,"\n")+">\x0D\x0A"+
  				"From: \""+io.attr("from")+"\" <"+io.attr("from")+">\x0D\x0A"+
  				"To: \""+io.attr("to")+"\" <"+io.attr("to")+">\x0D\x0A"+
  				"Subject: =?utf8?B?"+SYS.strEncode(io.attr("topic"),"Base64")+"?=\x0D\x0A"+
  				"Date: "+SYS.system("LANG=en date \"+%a, %d %b %Y %T %z\"").parse(0,"\n")+"\x0D\x0A"+
  				//"Date: "+SYS.strftime(SYS.time(),"%a, %d %b %Y %T %z")+"\x0D\x0A"+
  				"X-Mailer: OpenSCADA "+reqVer.text()+"\x0D\x0A"+
  				"Content-type: text/plain;charset=utf-8\x0D\x0A\x0D\x0A"+
  				io.text()+"\x0D\x0A"+
  				"\x0D\x0A.\x0D\x0A";	//End for code 354
  	rez = tr.messIO(data);
  	while(rez.length && rez.slice(-2) != "\x0D\x0A" && (trez=tr.messIO("")).length) rez += trez;
  	if(!rez.length)	{ io.setAttr("err", "100:"+tr("No response.")); return; }
  	if(rez.toInt() != 250)	{ io.setAttr("err", "105:"+tr("DATA send error: %1.").replace("%1",rez)); return; }

  	//Send QUIT
  	rez = tr.messIO("QUIT\x0D\x0A");
  	while(rez.length && rez.slice(-2) != "\x0D\x0A" && (trez=tr.messIO("")).length) rez += trez;

  	//SYS.messInfo("SMTP", "Response: "+rez);

  	//Disconnect from the SMTP-server
  	tr.start(false);
  }

  if(!tr.isEVal() && !io.isEVal() && io.attr("ProtIt") == "SMTP") { SMTP(); return; }

  //--------------------------------------------
  //Request form of the UserProtocol ProtIt="SMS":
  //--------------------------------------------
  //<cmd pin="1111" tel="+380XXXXXXXXX" text="{0|1}" err="1:Error">{SMSText}</cmd>
  //  cmd - command, for now only "send" allowed;
  //  pin - PIN code to the SIM card access;
  //  tel - telephone number of the receiver (remote cell phone or GSM modem);
  //  text{0,1} - SMS in the text mode, only ASCII;
  //  SMSText - the message text;
  //  err - sets for the request result.
  function SMS( ) {
  	//Transport's timings check
  	if(tr.timings() != "5000:100")	tr.timings("5000:100");
  	io.setAttr("err", "");
  	if(io.name() == "send") {
  		tel = io.attr("tel");
  		if(!tel.length || tel[0] != "+") { io.setAttr("err", "100:"+tr("Telephone number error.")); return; }

  		//Disable ECHO
  		rez = tr.messIO("ATE0\r");
  		while(rez.length && (trez=tr.messIO("")).length) rez += trez;
  		if(rez.indexOf("OK\r") < 0) {
  			io.setAttr("err", "101:"+tr("Error disabling ECHO: %1").replace("%1",rez));
  			return;
  		}

  		//Set PIN
  		if(io.attr("pin").length) {
  			//Check for PIN
  			rez = tr.messIO("AT+CPIN?\r");
  			while(rez.length && (trez=tr.messIO("")).length) rez += trez;
  			if(rez.indexOf("OK\r") < 0)	{ io.setAttr("err", "102:"+tr("Error checking for PIN-code: %1").replace("%1",rez)); return; }
  			if(rez.indexOf("+CPIN: READY\r") < 0) {	//PIN is needed
  				rez = tr.messIO("AT+CPIN="+io.attr("pin")+"\r");
  				while(rez.length && (trez=tr.messIO("")).length) rez += trez;
  				if(rez.indexOf("OK\r") < 0)	{ io.setAttr("err", "102:"+tr("Error setting PIN: %1").replace("%1",rez)); return; }
  			}
  		}

  		if(io.attr("text").toInt()) {	//SMS in the text mode
  			//Switch to Text SMS mode
  			rez = tr.messIO("AT+CMGF=1\r");
  			while(rez.length && (trez=tr.messIO("")).length) rez += trez;
  			if(rez.indexOf("OK\r") < 0)	{ io.setAttr("err", "103:"+tr("Error setting the SMS Text mode: %1").replace("%1",rez)); return; }

  			//Send the Telephone number
  			rez = tr.messIO("AT+CMGS=\""+tel+"\"\r");
  			while(rez.length && (trez=tr.messIO("")).length) rez += trez;
  			if(rez.indexOf(">") < 0)	{ io.setAttr("err", "104:"+tr("Error sending SMS: %1").replace("%1",rez)); return; }
  			rez = tr.messIO(io.text()+"\x1A");
  			while(rez.length && (trez=tr.messIO("")).length) rez += trez;
  			//for(var iTr = 0; iTr < 100 && rez.indexOf("OK\r") < 0; iTr++) rez += tr.messIO("");	//Up to 10 seconds wait for reply
  			if(rez.indexOf("OK\r") < 0)	{ io.setAttr("err", "104:"+tr("Error sending SMS PDU: %1").replace("%1",rez)); return; }
  		}
  		else {	//SMS in the PDU mode
  			// Switch to PDU SMS mode
  			rez = tr.messIO("AT+CMGF=0\r");
  			while(rez.length && (trez=tr.messIO("")).length) rez += trez;
  			if(rez.indexOf("OK\r") < 0)	{ io.setAttr("err", "103:"+tr("Error setting the SMS PDU mode: %1").replace("%1",rez)); return; }

  			//Prepare PDU
  			pdu = "001100";	//SMS center number (default) + SMS-Submit
  			//Telephone number encode
  			tel = tel.slice(1);
  			pdu += tel.length.toString(16,2) + "91";	//Telephone length and type
  			while(tel.length < 12) tel += "F";
  			for(i = 0; i < 6; i++) pdu += tel[i*2+1]+tel[i*2];
  			//Message encode
  			text = SYS.strCodeConv(io.text(),"","UCS2");
  			if((text.length/2) > 70)	text = text.slice(0,140);
  			//{ io.setAttr("err", "104:"+tr("Too long length (%1) of the message.").replace("%1",(text.length/2).toString())); return; }
  			pdu += "0018C1"+(text.length).toString(16,2);
  			for(i = 0; i < text.length/2; i++) pdu += text.charCodeAt(i*2+1).toString(16,2)+text.charCodeAt(i*2).toString(16,2);
  			//SYS.messDebug("TEST SMS","PDU :"+pdu);

  			// Send the PDU message
  			rez = tr.messIO("AT+CMGS="+(pdu.length/2-1)+"\r");
  			while(rez.length && (trez=tr.messIO("")).length) rez += trez;
  			if(rez.indexOf(">") < 0)	{ io.setAttr("err", "104:"+tr("Error sending SMS: %1").replace("%1",rez)); return; }
  			rez = tr.messIO(pdu+"\x1A");
  			while(rez.length && (trez=tr.messIO("")).length) rez += trez;
  			//for(var iTr = 0; iTr < 100 && rez.indexOf("OK\r") < 0; iTr++) rez += tr.messIO("");	//Up to 10 seconds wait for reply
  			if(rez.indexOf("OK\r") < 0)	{ io.setAttr("err", "104:"+tr("Error sending SMS PDU: %1").replace("%1",rez)); return; }
  			//SYS.messDebug("TEST SMS","PDU REZ :"+rez);
  		}
  		io.setAttr("err", "0");
  	}
  }

  if(!tr.isEVal() && !io.isEVal() && io.attr("ProtIt") == "SMS")	{ SMS(); return; }

  //---------------------------
  //The notification dispatcher
  //---------------------------
  if(f_start) {
  	queue = new Object();
  	queueSMS = new Object();
  	prTm = SYS.time();
  	prTmU = 0;
  	emailSentN = SMSSentN = 0;
  	emailTrAddr_ = emailTrAddr;
  	SMSTrAddr_ = SMSTrAddr;
  	SMTPTr = emailTrAddr.length ? SYS.Transport.nodeAt(emailTrAddr, ".") : false;
  	SMSTr = SMSTrAddr.length ? SYS.Transport.nodeAt(SMSTrAddr, ".") : false;
  	return;	//Don't real process at start
  }
  if(f_stop)	{ emailState = SMSState = ""; return; }
  if(!SMTPTr || emailTrAddr_ != emailTrAddr) {
  	SMTPTr = emailTrAddr.length ? SYS.Transport.nodeAt(emailTrAddr, ".") : false;
  	emailTrAddr_ = emailTrAddr;
  }
  if(!SMSTr || SMSTrAddr_ != SMSTrAddr)	{
  	SMSTr = SMSTrAddr.length ? SYS.Transport.nodeAt(SMSTrAddr, ".") : false;
  	SMSTrAddr_ = SMSTrAddr;
  }

  //Current alarms reading, and the queue of dispatching update
  mess = SYS.Archive.messGet(prTm, SYS.time(), messCat, abs(messLev), "<buffer>");
  for(iM = 0; iM < mess.length; iM++) {
  	oM = mess[iM];
  	if((oM.tm == prTm && oM.utm <= prTmU) || (messLev < 0 && oM.level >= 0))	continue;

  	if(emailTrAddr.length)	queue[oM.level.toString()+oM.tm.toString()+oM.categ] = oM;
  	if(SMSTr)	queueSMS[oM.level.toString()+oM.tm.toString()+oM.categ] = oM;

  	if((oM.tm*1e6+oM.utm) > (prTm*1e6+prTmU))	prTm = oM.tm, prTmU = oM.utm;
  	//SYS.messInfo("NTF","Queue mess: "+oM.mess);
  }

  //The notifications mail queue process in a cycle limited by overall time
  stTm = SYS.time();
  emailQueueN = 0;
  emailErr = "";
  for(var nM in queue) {
  	if(!SMTPTr)	break;
  	if((SYS.time()-stTm) > tmOut)	{ emailQueueN++; continue; }
  	oM = queue[nM];
  	//SYS.messInfo("NTF","Send mess \""+nM+"\": "+oM.mess);

  	topic = emailTopic + " (" + ((oM.level < 0)?tr("Alarm"):tr("Norm")) + ")";
  	mess = emailMess + SYS.strftime(oM.tm) + ": " + oM.mess;

  	tr = SMTPTr, io = SYS.XMLNode("send");
  	io.setAttr("ProtIt", "SMTP").setAttr("auth", emailAuth).setAttr("from", emailSender).setAttr("to", emailReceiver).setAttr("topic", topic).setText(mess);
  	SMTP();
  	//SYS.messInfo("NTF", "Send error: "+io.attr("err"));
  	if(!io.attr("err").toInt()) { delete queue[nM]; emailSentN++; }
  	else {
  		emailQueueN++;
  		if(!emailErr.length)	emailErr = io.attr("err");
  	}
  	io = tr = EVAL;

  	/*req = "sendemail -q -f " + emailSender + " -t " + emailReceiver +
  			" -u \"=?utf8?B?" + SYS.strEncode(topic,"Base64") + "?=\" -m \"" + mess + "\" -s " + emailTrAddr;
  	if(emailAuth.length)	req += " -xu " + emailAuth.parse(0,":") + " -xp " + emailAuth.parse(1,":");
  	req += " -o tls=no -o message-charset=utf8";
  	//SYS.messInfo("NTF","Send mess: "+req);
  	rez = SYS.system(req, true);
  	if(!rez) { delete queue[nM]; emailSentN++; }
  	else {
  		emailQueueN++;
  		if(!emailErr.length)	emailErr = req.attr("err");
  	}*/
  }
  if(!SMTPTr)	emailState = "Disabled!";
  else {
  	emailState = tr("Sent %1. In queue %2.").replace("%1",emailSentN.toString()).replace("%2",emailQueueN.toString());
  	if(emailErr.length) emailState += " "+tr("Error: %1.").replace("%1",emailErr);
  }

  //The notifications SMS queue process in a cycle limited by overall time
  stTm = SYS.time();
  SMSQueueN = 0;
  SMSErr = "";
  for(var nM in queueSMS) {
  	if(!SMSTr)	break;
  	if((SYS.time()-stTm) > tmOut)	{ SMSQueueN++; continue; }
  	oM = queueSMS[nM];
  	//SYS.messInfo("NTF","Send SMS \""+nM+"\": "+oM.mess);

  	mess = oM.mess;
  	tr = SMSTr, io = SYS.XMLNode("send");
  	io.setAttr("ProtIt", "SMS").setAttr("pin", SMSPin).setAttr("text",SMSTextMd).setAttr("tel", SMSTel).setText(mess);
  	SMS();
  	if(!io.attr("err").toInt()) { delete queueSMS[nM]; SMSSentN++; }
  	else {
  		SMSQueueN++;
  		if(!SMSErr.length)	SMSErr = io.attr("err");
  	}
  	io = tr = EVAL;
  }
  if(!SMSTr)	SMSState = "Disabled!";
  else {
  	SMSState = tr("Sent %1. In queue %2.").replace("%1",SMSSentN.toString()).replace("%2",SMSQueueN.toString());
  	if(SMSErr.length) SMSState += " "+tr("Error: %1.").replace("%1",SMSErr);
  }


ID: UPS
NAME: Uninterruptible Power Supply
uk#NAME: Джерело Безперебійного Живлення
ru#NAME: Источник Бесперебойного Питания
DESCR:
  Data combination of the Uninterruptible Power Supply in a complex object of the attribute "All items". The template designed to use together with the DAQ-module "System" in the part "UPS" and to represent this data by the frame "Object properties" as a complex object with properties, signalling at single borders and writing.

  Author: Roman Savochenko <roman@oscada.org>
  Sponsored by: DIYA LTD
  Version: 1.3.0
  License: GPLv2

uk#DESCR:
  Об'єднання даних Джерела Безперебійного Живлення у комплексному об'єкті атрибуту "Всі елементи". Шаблон розроблено для використання із модулем джерела даних "Система" у частині "ДБЖ" та представлення цих даних кадром "Властивості об'єкту" як комплексний об'єкт із властивостями, сигналізацією за окремими границями та записом.

  Автор: Роман Савоченко <roman@oscada.org>
  Спонсоровано: ТОВ "ДІЯ"
  Версія: 1.3.0
  Ліцензія: GPLv2

PROGRAM:
  JavaLikeCalc.JavaScript
  if(f_start)	{ srcPrm = false; items = new Object(); alDelay_ = 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(alSup) {
  	if(f_err.toInt())	this.alarmSet(DESCR+": "+tr("SUPPRESSED"), 1);
  	f_err = "0";
  }
  else {
  	if(tErr.toInt() && tErr.toInt() != f_err.toInt() && this.cntr().status().toInt())	return;
  	if(alDelay > 0 && alDelay_ <= 0 && tErr.toInt() != f_err.toInt())	tErr1 = tErr.toInt();
  	if(alDelay > 0 && alDelay_ > 0 && tErr.toInt() != tErr1)	{ alDelay_ = 0; tErr1 = tErr.toInt(); }
  	if(alDelay > 0 && alDelay_ < alDelay){ alDelay_ += 1/f_frq; return; }
  	if(tErr.toInt())	this.alarmSet(DESCR+": "+tErr.parse(1,":"), -(2+alLev));
  	else	this.alarmSet(DESCR+": "+tr("NORMA"), 1);
  	f_err = tErr;
  	alDelay_ = 0;
  }


ID: initConsAssignTrs
NAME: Initiative connections processing for assigned output transports
uk#NAME: Опрацювання ініціативних підключень щодо асоціативних вихідних транспортів
ru#NAME: Обработка инициативных подключений на предмет ассоциативных выходных транспортов
DESCR:
  The template of processing input initiative connections was created to provide the latest chain of implementation and support for conception of data acquisition in the passive mode and the initiative connection, that is — the control of associative connections, created by the input transport at each connection.

  The function of creation associative output transports at connections is currently only supported by the module "Sockets" and for TCP-sockets.

  The control of associative transport means:
    - obtaining a list of the associative transports, by the function assTrsList() of the input transports;
    - reading from new transports (opened) of identification information, which currently represents only the source object identifier;
      - search, by the received identifier, the source object and assigning to it of this transport;
      - registering in the attribute "prcTr" of the object type.
    - checking of existing transports for their closure (detachment), for which performed the deregistration in the attribute "prcTr" of the object type and the establishment of the source object in the empty value; disconnected output associated transports are reused by the input one upon receiving a new connection then it is switched on.

  The template can control the containers of data source objects, constructed both as DAQ-objects of the controllers and logical level parameters, what representing the data source and having a transport address definition field, and what generally defined by the configuration field "srcObjPath" of the format {CntrAddr}:{TrCntrFldAddr}, where:
    - CntrAddr — container address, for example: "ModBus" — for DAQ-objects of the controllers, "LogicLev.CntrPLC" — for logical level parameters;
    - TrCntrFldAddr — address of the transport control field in the source object, for example — "%2fcntr%2fcfg%2fADDR" for "ModBus"; what can be obtained in a configurator at the history of pointing on the control field in the status line.

  Author: Roman Savochenko <roman@oscada.org>
  Sponsored by: BLUE STAR GROUP Ltd
  Version: 1.1.0
  License: GPLv2

uk#DESCR:
  Шаблон служби опрацювання вхідних ініціативних підключень створено для надання останньої ланки реалізації та підтримки концепції збору даних у пасивному режимі та ініціативного підключення, а саме — контролю асоціативних транспортів, створюваних вхідним транспортом за кожним підключенням.

  Функцію створення вихідних асоціативних транспортів за підключенням на вхідний наразі підтримує лише модуль транспортів "Сокети" та для TCP-сокетів.

  Контроль асоціативних транспортів передбачає:
    - отримання переліку асоціативних транспортів, функцією вхідного транспорту assTrsList();
    - читання із нових транспортів (відкритих) ідентифікаційної інформації, яка наразі репрезентує тільки ідентифікатор об'єкту джерела;
      - пошук, за отриманим ідентифікатором, об'єкта джерела та призначення йому адреси цього транспорту;
      - реєстрацію у атрибуті об'єктного типу "prcTr".
    - перевірка діючих транспортів на предмет їх закриття (від'єднання), щодо чого здійснюється дереєстрація у атрибуті об'єктного типу "prcTr" та встановлення об'єкту джерела порожнього значення; вимкнені вихідні асоціативні транспорти повторно використовуються вхідним за отриманням нового підключення, після чого він вмикається.

  Шаблон може керувати контейнерами об'єктів джерел даних, побудованих як у вигляді DAQ-об'єктів контролерів, так і параметрів логічного рівня, що репрезентують джерело даних та мають поле визначення адреси транспорту та що загалом визначається конфігураційним полем "srcObjPath" із форматом {CntrAddr}:{TrCntrFldAddr}, де:
    - CntrAddr — адреса контейнеру, наприклад: "ModBus" — для DAQ-об'єктів контролерів, "LogicLev.CntrPLC" — для параметрів логічного рівня;
    - TrCntrFldAddr — адреса поля контролю транспорту у об'єкті джерела, наприклад — "%2fcntr%2fcfg%2fADDR" для "ModBus"; що може бути отримано у конфігураторі за історією наведення на поля контролю у рядку статусу.

  Автор: Роман Савоченко <roman@oscada.org>
  Спонсорування: ТОВ BLUE STAR GROUP
  Версія: 1.1.0
  Ліцензія: GPLv2

PROGRAM:
  JavaLikeCalc.JavaScript
  if(f_start) {
  	inTransport_ = "", inTr = EVAL;
  	prcTr = new Object();
  }

  //Check for the transport change and connect
  tErr = "";
  if(inTr.isEVal() || inTransport != inTransport_)	{
  	inTr = SYS.Transport.Sockets["in_"+inTransport];
  	inTransport_ = inTransport;
  }

  if(inTr.isEVal())	tErr = "1:"+tr("Input transport '%1' error.").replace("%1",inTransport);
  else if(!(CNTR_O=SYS.DAQ.nodeAt(srcObjPath.parse(0,":"),".")))
  	tErr = "2:"+tr("Error the source object path '%1'.").replace("%1", srcObjPath.parse(0,":"));
  else if(!(CntrFldPath=srcObjPath.parse(1,":")).length)
  	tErr = "3:"+tr("The control field path is empty.");
  else {
  	isLogPrm = srcObjPath.parse(0,":").parse(1).length;

  	outTrs = inTr.assTrsList();
  	for(iTr = 0; iTr < outTrs.length; iTr++) {
  		oTrNm = outTrs[iTr];
  		// The transport is present and active
  		if(!(oTrO=SYS.Transport.Sockets["out_"+oTrNm]).isEVal() && oTrO.start()) {
  			//  and not registered
  			if(prcTr[oTrNm].isEVal()) {
  				//   reading the source identifier
  				idSeq = oTrO.messIO("").parse(0, ":");
  				//   stop for empty-missed identification or missed PLC object
  				if(!idSeq.length || (PLC_O=CNTR_O[(isLogPrm?"prm_":"")+idSeq]).isEVal())	{
  					oTrO.start(false);
  					if(idSeq.length)
  						SYS.messNote("initConsAssignTrs", tr("The requested identificator '%1' is mіssing in the container '%2' of the data source objects!").replace("%1",idSeq).replace("%2",srcObjPath.parse(0,":")));
  					continue;
  				}

  				req = SYS.XMLNode("get").setAttr("path",PLC_O.nodePath()+"/"+CntrFldPath);
  				SYS.cntrReq(req);
  				//   stop for not empty and not equal value and register already the transports
  				if(((tVl=req.text()).length && tVl != oTrNm && !outTrs[tVl].isEVal()))	{ oTrO.start(false); continue; }

  				//   connect the transport to a PLC object
  				if(outTrTm.length)	oTrO.timings(outTrTm);
  				prcTr[oTrNm] = idSeq;
  				req.setName("set").setText("Sockets."+oTrNm);
  				SYS.cntrReq(req);
  			}
  		}
  		// is not present or active
  		else if(!prcTr[oTrNm].isEVal() && !(PLC_O=CNTR_O[(isLogPrm?"prm_":"")+prcTr[oTrNm]]).isEVal()) {
  			delete prcTr[oTrNm];
  			SYS.cntrReq(SYS.XMLNode("set").setAttr("path",PLC_O.nodePath()+"/"+CntrFldPath).setText(""));
  		}
  	}
  	delete oTrO;
  }

  //Error set
  if(tErr.length)	f_err = tErr;
  else f_err = "0";


