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


# tmplib_base

ID: digAlarm
NAME: Alarm digital
uk#NAME: Сигн. дискретна
ru#NAME: Сигн. дискретная
DESCR: Alarm from a digital parameter.
uk#DESCR: Сигналізація за дискретним параметром.
ru#DESCR: Сигнализация по дискретному параметру.
PROGRAM:
  JavaLikeCalc.JavaScript
  if(f_start) {
  	f_err = "0", prevVar = EVAL_REAL;
  	//Prepare data for preprocessing
  	inPrcId = this.nodePath("_");
  	inPrcLng = "JavaLikeCalc.JavaScript";
  	inPrcArgs = new Object();
  	inPrcArgs.this = this;
  	inPrcArgs.ctx = new Object();
  	return;
  }

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

  //State set
  tErr = "0", levErr = 0;
  if(in.isEVal()) {
  	tErr = "1:"+tr("No data or connection with source");
  	levErr = -5;
  	st_open = st_close = in;
  }
  else {
  	if(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(tErr.toInt() && tErr.toInt() != f_err.toInt())
  	this.cntr().alarmSet((NAME.length?NAME:SHIFR)+": "+DESCR+": "+tErr.parse(1,":"), levErr, SHIFR);
  else if(f_err.toInt() && !tErr.toInt())
  	this.cntr().alarmSet((NAME.length?NAME:SHIFR)+": "+DESCR+": "+tr("NORMA"), 1, SHIFR);
  f_err = tErr;


ID: simleBoard
NAME: Analog alarm by borders
uk#NAME: Сигн. аналог. за границями
ru#NAME: Сигн. аналог. по границам
DESCR: The template of simple parameter included boders and dimension variable.
uk#DESCR: Шаблон простого параметру з перевіркою границь та одиницею виміру.
ru#DESCR: Шаблон простого параметра с проверкой границ и единицей измерения.
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: Diskret parameters block
uk#NAME: Блок дискр. параметрів
ru#NAME: Блок дискр. параметров
DESCR: The block for union of Diskret parameters for one device control.
uk#DESCR: Блок для збору дискретних параметрів, керуючих одним апаратом.
ru#DESCR: Блок для сборки дискретных параметров управляющих одним аппаратом.
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
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 (Unif)
uk#NAME: Ручний ввід (Уніф)
ru#NAME: Ручной ввод (Униф)
DESCR: Unified template for manual input signals.
uk#DESCR: Уніфікований шаблон для ручного вводу значень сигналів.
ru#DESCR: Унифицированный шаблон ручного ввода сигнала.
PROGRAM:
  JavaLikeCalc.JavaScript
  if(f_start)	f_err = "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)	f_err = "0";
  else {
  	if(tErr.toInt() && tErr.toInt() != f_err.toInt())
  		this.cntr().alarmSet((NAME.length?NAME:SHIFR)+": "+DESCR+": "+tErr.parse(1,":"), levErr, SHIFR);
  	else if(f_err.toInt() && !tErr.toInt())
  		this.cntr().alarmSet((NAME.length?NAME:SHIFR)+": "+DESCR+": "+tr("NORMA"), 1, SHIFR);
  	f_err = tErr;
  }


ID: anUnif
NAME: Analog sign. (Unif)
uk#NAME: Аналог. сигнал (Уніф)
ru#NAME: Аналог. сигн. (Униф)
DESCR: Unified template for analog input signals processing.
uk#DESCR: Уніфікований шаблон для обробки аналогових вхідних сигналів.
ru#DESCR: Унифицированный шаблон обработки аналогового входного сигнала.
PROGRAM:
  JavaLikeCalc.JavaScript
  if(f_start) {
  	if(alSup == 0) f_err = "0";
  	prevVar = EVAL_REAL;
  	conDelay_ = 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 {
      plcDif = abs(pMax-pMin);
      in = pMin + plcDif/2 + 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()) {
  	//if(alDelay > 0 && conDelay_ < alDelay){ conDelay_ += 1/f_frq; return; }
  	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) {
  	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;
  	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 == 1)	f_err = "0";
  else {
  	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.cntr().alarmSet((NAME.length?NAME:SHIFR)+": "+DESCR+": "+tErr.parse(1,":"), levErr, SHIFR);
  	else if(f_err.toInt() && !tErr.toInt())
  		this.cntr().alarmSet((NAME.length?NAME:SHIFR)+": "+DESCR+": "+tr("NORMA"), 1, SHIFR);
  	toSave = (alSup == 2 && f_err != tErr);
  	f_err = tErr;
  	if(toSave) SYS.cntrReq(SYS.XMLNode("save").setAttr("path",this.nodePath()+"/%2fobj").setAttr("force",1));
  	conDelay_ = 0;
  }


ID: digitBlockUnif
NAME: Diskret block (Unif)
uk#NAME: Блок дискретних (Уніф)
ru#NAME: Блок дискр. (Униф)
DESCR: The block for union of Diskret parameters for one device control.
uk#DESCR: Блок поєднання дискретних сигналів контролю одним пристроєм.
ru#DESCR: Блок для дискретных параметров управляющих одним аппаратом.
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 sign. (Unif, stats)
uk#NAME: Імпульсний ПІД сигнал (Уніф, стани)
ru#NAME: ПИД импульсный сигнал (Униф, состояния)
DESCR: The unified template for process analog signals with properties impulse PID.
uk#DESCR: Уніфікований шаблон для обробки аналогового сигналу з властивостями імпульсного ПІД.
ru#DESCR: Унифицированный шаблон обработки аналогового сигнала со свойствами импульсного ПИД.
PROGRAM:
  JavaLikeCalc.JavaScript
  if(f_start) f_err = "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) {
  	//var = dmsk ? max+plcExcess*(max-min)/100 : min-plcExcess*(max-min)/100;
  	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;
  }

  if(!f_err.toInt() && tErr.toInt()) this.cntr().alarmSet((NAME.length?NAME:SHIFR)+": "+DESCR+": "+tErr.parse(1,":"), -4, SHIFR);
  else if(f_err.toInt() && !tErr.toInt()) this.cntr().alarmSet((NAME.length?NAME:SHIFR)+": "+DESCR+": "+tr("NORMA"), 1, SHIFR);
  f_err = tErr;


ID: anUnifSt
NAME: Analog sign. (Unif, stats)
uk#NAME: Аналог. сигнал (Уніф, стани)
ru#NAME: Аналог. сигн. (Униф, состояния)
DESCR: Unified template for analog input signals processing.
uk#DESCR: Уніфікований шаблон для обробки аналогових вхідних сигналів.
ru#DESCR: Унифицированный шаблон обработки аналогового входного сигнала.
PROGRAM:
  JavaLikeCalc.JavaScript
  if(f_start) {
  	if(alSup == 0) f_err = "0";
  	prevVar = EVAL_REAL;
  	conDelay_ = 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 {
  		plcDif = abs(pMax-pMin);
  		in = pMin + plcDif/2 + 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()) {
  	//if(alDelay > 0 && conDelay_ < alDelay){ conDelay_ += 1/f_frq; return; }
  	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 == 1)	f_err = "0";
  else {
  	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.cntr().alarmSet((NAME.length?NAME:SHIFR)+": "+DESCR+": "+tErr.parse(1,":"), levErr, SHIFR);
  	else if(f_err.toInt() && !tErr.toInt())
  		this.cntr().alarmSet((NAME.length?NAME:SHIFR)+": "+DESCR+": "+tr("NORMA"), 1, SHIFR);
  	toSave = (alSup == 2 && f_err != tErr);
  	f_err = tErr;
  	if(toSave) SYS.cntrReq(SYS.XMLNode("save").setAttr("path",this.nodePath()+"/%2fobj").setAttr("force",1));
  	conDelay_ = 0;
  }


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

  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(tErr.toInt() && tErr.toInt() != f_err.toInt())
  	this.cntr().alarmSet((NAME.length?NAME:SHIFR)+": "+DESCR+": "+tErr.parse(1,":"), -(2+alLev), SHIFR);
  else if(f_err.toInt() && !tErr.toInt())
  	this.cntr().alarmSet((NAME.length?NAME:SHIFR)+": "+DESCR+": "+tr("NORMA"), 1, SHIFR);
  f_err = tErr;


# lib_Controllers

ID: prescr
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 <rom_as@oscada.org>
  Sponsor: Vasiliy Grigoriev from "Vacuum technologies laboratory (http://e-beam.ru)".
  Version: 1.0.0

FORMULA:
  clcCnt++;

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

  //Check to commands controller present
  comCntrO = false;
  if(comsCntr.length)	comCntrO = 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]];
  			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 == 1)) {
  	curMode = mode;
  	if((curMode == 1 || curMode == 2) && comCntrO) {
  		var cL = comCntrO.nodeList("prm_");
  		for(i_c = 0; i_c < cL.length; i_c++)
  			comCntrO[cL[i_c]].pause.set(curMode==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 = 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 = true;
  		}
  		else if(curComPos >= 0 && curComPos < curComNd.childSize()) {
  			comEl = curComNd.childGet(curComPos);
  			//Stop process
  			if(mode == 0) {
  				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);
  				}
  				//Update steps status, up to current comand
  				for(comElN = work, comPos = 0, comLev = 0, comCur = true; true; comPos++) {
  					if(comPos >= comElN.childSize()) {
  						if((comElN=comElN.parent())) {
  							comLev--;
  							comPos = comElN.attr("seekPos").toInt();
  							comCur = comElN.attr("comCur").toInt();
  							continue;
  						}
  						break;
  					}
  					comElI = comElN.childGet(comPos);
  					isCurCmd = comCur && comLev == (curComLev-1) && curCom.parse(comLev,":").toInt() == comPos;
  					curComPI = comCntrO["prm_"+comLs[comElI.attr("id")].prmID];
  					if(isCurCmd || (curComPI.run.get() && comElI.attr("rez").toInt() != 1 && comElI.attr("rez").toInt() > -10))
  					{
  						rez = curComPI.rez.get();
  						if(isCurCmd && rez.toInt() > 0) toNext = true;
  						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;
  						}
  						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) break;
  					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+"';");
  			}
  		}
  	}
  }
  mode = curMode;


ID: test
NAME: test
ru#NAME: test
DESCR:
  Different tests of the JavaLikeCalc language for execution into the controller mode.
  Author: Roman Savochenko
  Version: 1.0.0

FORMULA:
  using Special.FLibSYS;

  out+=10;
  if(out>100) out=0;

  test = (10).toString(16,2,true);
  test = (-10.34).toFixed(4,8);

  //Request prepare
  //req = SYS.XMLNode("#").setAttr("ProtIt","DCON").setAttr("addr",10);
  //Send request
  //SYS.Transport["Serial"]["out_TestDCON"].messIO(req,"UserProtocol");
  //if(!req.attr("err").length) SYS.messDebug("TEST REQ","RES: "+req.text());

  //test = "Text \n value[\041abc\x21].";

  //test = arguments[4];
  //arguments[4] = 10;

  //test="Java123Script".search(new RegExp("script","i"));
  //text = "Javascript3\"sdf\"3javaScript __ javascript";
  //test = text.replace(4,3,"67");
  //test = text.replace("3","55");
  //test = text.replace(new RegExp("javascript","ig"),"JavaScript");//
  //test = text.replace(new RegExp("\"([^\"]*)\"","g"),"``$1''");
  //text = "1 плюс 2 плюс 3";
  //test = text.match("\\d+","g");
  //text = "Посетите мою домашнюю страницу http://www.isp.com/~david";
  //test = text.match("(\\w+):\\/\\/([\\w.]+)\\/(\\S*)");
  //test = "1,2, 3 , 4 ,5".split(new RegExp("\\s*,\\s*"));
  //test = "hello <b>world</b>".split(new RegExp("(<[^>]*>)"));
  //var p = new RegExp("(\\d\\d)[-/](\\d\\d)[-/](\\d\\d(?:\\d\\d)?)","");
  //test = p.test("abc12/30/1969def");

  /*CRC = new Array(0,1,2,3,4,5);vSz = 3
  hi=CRC[out%6];
  test = hi;*/

  //test = SYS.Transport.Sockets.out_testModBus.messIO("123456");

  /*obj = new Object();
  obj["test1"]=1;l
  obj["test2"]=1;
  for( var i in obj ) SYS.messDebug("test","Prop: "+i);
  SYS.messDebug("test","Props test");*/

  //vl = SYS.strFromCharCode(100,200,50,60);
  //test = vl.charCodeAt(1);

  //test = SYS.system("ps -Ao pid,comm");

  //ModBus.Unidrive.pos.pos=out;
  //ModBus.testRTU.test.pos=out;
  //test = rand(offset*0.4);
  //val="Test";
  //if( val=="Test1" || val=="Test2" ) test="TestN"; else test="Test";

  //test1=new Array(1,"a",2,"b",3,"c",4);
  //test1[7]=new Array(5,6,7);
  //test=test1[7][1];

  //test1="ab;cde;fgh;jk;lm";
  //test = test1.split(";").join();

  //req = xmlNode("get").setAttr("path","/%2fgen%2fid");
  //test = xmlCntrReq(req);
  //test = req.text();

  /*test1 = vArh("DAQ.System.AutoDA.CPULoad.load");
  test2 = test1.FFT(0,60);
  test = "";
  for( i = 0; i < test2.length; i++ ) test += ""+test2[i]+";";*/

  //messPut("cron",0,"Time: "+tmFStr(tmTime()));

  /*req = SYS.XMLNode();
  test = req.load("test1.xml",true);*/
  //for( i = 0; i < req.childSize(); i++ )
  //  test += req.childGet(i).attr("id")+"; ";
  /*sutm = 0; stm = SYS.time(sutm);
  req.save(0,"test2.xml");
  eutm = 0; etm = SYS.time(eutm);
  test = 1e6*(etm-stm)+(eutm-sutm);*/

  //test = strDec4Bin(Transport.Sockets.out_testModBus.messIO(strEnc2Bin("15 01 00 00 00 06 01 03 00 00 00 05")));

  /*req = SYS.XMLNode("GET");
  req.setAttr("URI","/");
  SYS.Transport.Sockets.out_testHTTP.messIO(req,"HTTP");
  test = req.text();*/

  /*req = SYS.XMLNode("POST");
  req.setAttr("URI","/WebUser/FlowTec.txt");
  cntNode = req.childAdd("cnt").setAttr("name","pole0").setAttr("filename","Object2-k001-100309-17.txt");
  cntNode.childAdd("prm").setAttr("id","Content-Type").setText("text/plain");
  cntText = "Object2-k001\r\n";
  cntText += "\r\n";
  cntText += "v002\r\n";
  cntText += " n1\r\n";
  cntText += "  09.03.10 16   Polnyj    7155.25    216.0  32.000  17.5\r\n";
  cntText += "v005\r\n";
  cntText += " n1\r\n";
  cntText += "  09.03.10 16   Polnyj     188.81    350.0   4.000  40.0\r\n";
  cntText += "\r\n";
  cntNode.setText(cntText);
  SYS.Transport.Sockets.out_testHTTP.messIO(req,"HTTP");*/

  //test = SYS.UI.VCAEngine["ses_AGLKS"].alrmSndPlay();
  //test = "1;2;5;7;9";
  //test = "1;2;5;7;9".type();

  //SYS.messDebug("test",strEnc2Bin("68 74 74 70 3a 2f 2f 77 77 77 2e 77 33 2e 6f 72 67 2f 32 30 30 30 2f 30 39 2f 78 6d 6c 64 73 69 67 23 72 73 61 2d 73 68 61 31"));

  //test = SYS.DAQ.ModBus.testTCP.test.a_8_1_1_ПС_ОПД_стенд_температура__ОПД_.get();

  /*req = SYS.XMLNode("get").setAttr("path","/%2fgen%2fid");
  rez = SYS.cntrReq(req,"loop");
  test = req.text();*/

  /*DBTbl=SYS.BD.MySQL.GenDB.SQLReq("SELECT * from DB;");
  for( var i_rw = 0; i_rw < DBTbl.length; i_rw++ )
  {
    var rec = "";
    for( var i_fld = 0; i_fld < DBTbl[i_rw].length; i_fld++ )
      rec += DBTbl[i_rw][i_fld]+"\t";
    SYS.messDebug("TEST DB","Row "+i_rw+": "+rec);
  }*/


ID: test1
NAME: test1
uk#NAME: test1
DESCR:
  Different tests of the JavaLikeCalc language for execution into the controller mode.
  Author: Roman Savochenko
  Version: 1.0.0

FORMULA:
  //clc=0;
  //First getting previous time
  //if(!p_tm){ p_tm = Special.FLibSYS.tmTime(); break; }

  //Get curent time
  //c_tm = Special.FLibSYS.tmTime()-2;

  //Open value archive
  //a_id = Special.FLibSYS.avalOpen("Archive.va_test");
  //if(a_id==-1) break;

  //Calc average archive
  //for(i_tm=p_tm;i_tm<c_tm;i_tm++)
  //{ 
  //  val = Special.FLibSYS.avalGetR(a_id,i_tm,0,"");
  //  rez = (rez*(i_tm-p_tm)+val)/(i_tm-p_tm+1);
  //  clc++;
  //}

  //Close value archive
  //Special.FLibSYS.avalClose(a_id);
  //p_tm=c_tm;


ID: ntfDispatch
NAME: Notifications dispatcher
DESCR:
  Notifications dispatcher by EMail and SMS for pointed messages of OpenSCADA messages buffer.
  Author: Roman Savochenko <rom_as@oscada.org>
  Sponsor: Oleksandr Knestyapin <olexanderrr@gmail.com>
  Version: 1.3.1

FORMULA:
  //Initial
  if(f_start) {
  	queue = new Object();
  	queueSMS = new Object();
  	prTm = SYS.time();
  	prTmU = 0;
  	emailSentN = SMSSentN = 0;
  	emailServer_ = emailServer;
  	SMTPTr = emailServer.length ? SYS.Transport.nodeAt(emailServer,".") : false;
  	SMSTrId_ = SMSTrId;
  	SMSTr = SMSTrId.length ? SYS.Transport.Serial.nodeAt("out_"+SMSTrId) : false;
  	return;	//Don't real process at start
  }
  if(f_stop)	{ emailState = SMSState = ""; return; }
  if(emailServer_ != emailServer) {
  	SMTPTr = emailServer.length ? SYS.Transport.nodeAt(emailServer,".") : false;
  	emailServer_ = emailServer;
  }
  if(SMSTrId_ != SMSTrId)	{
  	SMSTr = SMSTrId.length ? SYS.Transport.Serial.nodeAt("out_"+SMSTrId) : false;
  	SMSTrId_ = SMSTrId;
  }

  //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(emailServer.length)	queue[oM.level.toString()+oM.tm.toString()+oM.categ] = oM;
  	if(SMSTr)	queueSMS[oM.level.toString()+oM.tm.toString()+oM.categ] = oM;

  	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;

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

  	/*req = "sendemail -q -f " + emailSender + " -t " + emailReceiver +
  			" -u \"=?utf8?B?" + SYS.strEncode(topic,"Base64") + "?=\" -m \"" + mess + "\" -s " + emailServer;
  	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;
  	req = SYS.XMLNode("send"); req.setAttr("ProtIt", "SMS").setAttr("pin", SMSPin).setAttr("text",SMSTextMd).setAttr("tel", SMSTel).setText(mess);
  	SMSTr.messIO(req, "UserProtocol");
  	if(!req.attr("err").toInt()) { delete queueSMS[nM]; SMSSentN++; }
  	else {
  		SMSQueueN++;
  		if(!SMSErr.length)	SMSErr = req.attr("err");
  	}
  }
  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);
  }


# lib_servProc

ID: procArh
NAME: Archives recalc
uk#NAME: Перерахунок архівів
ru#NAME: Пересчёт архивов
DESCR:
  Value archives recalculation.
  Author: Roman Savochenko <rom_as@oscada.org>
  Version: 1.0.0

FORMULA:
  using Special.FLibSYS;

  //messPut("UserProc/ProcessArch",1,"Archive open");
  a_src = vArh(fromarch);
  a_dst = vArh(toarch);

  //messPut("UserProc/ProcessArch",1,"Archive process");

  bf_per = 100;	//Buffers period microseconds
  bf_size = 100000;	//Buffers size

  //Open value buffers
  bf_src = vArhBuf(1,bf_size,bf_per,true,true);
  bf_dst = vArhBuf(4,bf_size,bf_per,true,true);

  //Parse time string
  begtm = tmStrPTime(begs);
  endtm = tmStrPTime(ends);

  begwtm = begtm;
  while( begwtm<endtm )
  {
      //Get value
      endwtm = begwtm+bf_size*bf_per/1000000;
      if(endwtm>endtm) endwtm = endtm;
      messPut("UserProc/ProcessArch",1,"Values from: "+begwtm+", to: "+endwtm);
      bf_src.copy(a_src,begwtm,0,endwtm,0);

      buf_beg = begwtm; buf_beg_u = 0;
      buf_end = endwtm; buf_end_u = 0;
      while( !(buf_beg>=buf_end && buf_beg_u>buf_end_u) )
      {
          r_val = bf_src.get(buf_beg,buf_beg_u,true);
          if(r_val == EVAL_INT) bf_dst.set(EVAL_REAL,buf_beg,buf_beg_u);
          else bf_dst.set(200.*((10.*r_val/32768.)-1.)/4.,buf_beg,buf_beg_u);

          buf_beg_u++;
      }

      a_dst.copy(bf_dst,begwtm,0,endwtm,0);
      begwtm = endwtm;
  }


ID: crc16
NAME: CRC 16
DESCR:
  Standard Cyclic Redundancy Check (CRC) with free polynomial set, by default it is 0x8005. It isn't actual more by the common CRC implementing.
  Author: Roman Savochenko <rom_as@oscada.org>
  Version: 1.0.0

FORMULA:
  out = 0xFFFF;
  for(i = 0; i < in.length; i++) {
    out = out^in.charCodeAt(i);
    for(j = 0; j < 8; j++) out = (out&1) ? ((out>>1)^poly) : out >> 1;
  }


ID: releaseTests
NAME: TEST: Release
uk#NAME: Тести випуску
ru#NAME: Тесты выпуска
DESCR:
  OpenSCADA releases formal sets pack in list:
    - 0:System
    - 1:Security User/Group tests
    - 2:Transport subsystem tests
    - 3:Archive subsystem tests
    - 4:DB subsystem tests
    - 5:Protocol subsystem tests
    - 6:DAQ subsystem tests
    - 7:UI subsystem tests
    - 8:Special subsystem tests
  Author: Roman Savochenko <rom_as@oscada.org>
  Version: 1.0.0

FORMULA:
  nNm = "testNode";
  node  = false;		//Process node
  testREZ = "";		//Test rezult
  rez = "";

  //**********************************
  //Get config file name
  SYS.cntrReq(req=SYS.XMLNode("get").setAttr("path","/%2fgen%2fconfig"));
  configPath = req.text();
  //Save original config file
  SYS.fileWrite(configPath+".orig",SYS.fileRead(configPath));
  //Load config file tree
  cfgTree=SYS.XMLNode();
  cfgTree.load(configPath,true,true);

  //**********************************
  //System
  if(sub <= 0) {
  	testREZ = SYS.Special.SystemTests.XML(configPath);
  	rez += "<tr><td>Control interface: Test of the XML file parsing</td><td>"+testREZ+"</td></tr>\n";
  	testREZ = SYS.Special.SystemTests.SysContrLang("/Archive/FSArch/mess_StatErrors/%2fprm%2fst");
  	rez += "<tr><td>Control interface: Test of the control system language</td><td>"+testREZ+"</td></tr>\n";
  	testREZ = SYS.Special.SystemTests.Base64Code();
  	rez += "<tr><td>SYS: Tests of the Mime Base64 encoding algorithm</td><td>"+testREZ+"</td></tr>\n";
  }

  //**********************************
  //Security User/Group tests
  if(sub < 0 || sub == 1) {
  	testREZ = "PASSED";
  	// User
  	nAddr = "/Security/usr_"+nNm;
  	if(SYS.cntrReq(SYS.XMLNode("add").setAttr("path","/Security/%2fbr%2fusr_").setText(nNm)) != 0 || !(node=SYS.nodeAt(nAddr))) testREZ = "FAILED: user add";
  	else if(SYS.cntrReq(SYS.XMLNode("set").setAttr("path",nAddr+"/%2fprm%2fdscr").setText("Test")) != 0 || node.cfg("DESCR") != "Test") testREZ = "FAILED: change user";
  	else if(SYS.cntrReq(SYS.XMLNode("save").setAttr("path",nAddr+"/%2fobj")) != 0) testREZ = "FAILED: save user";
  	else if(SYS.cntrReq(SYS.XMLNode("set").setAttr("path",nAddr+"/%2fprm%2fdscr").setText("Test 1")) != 0 || 
  		SYS.cntrReq(SYS.XMLNode("load").setAttr("path",nAddr+"/%2fobj")) != 0 || node.cfg("DESCR") != "Test") testREZ = "FAILED: load user";
  	else {
  		node = false;
  		if(SYS.cntrReq(SYS.XMLNode("del").setAttr("path","/Security/%2fbr%2fusr_").setText(nNm)) != 0 || SYS.nodeAt(nAddr)) testREZ = "FAILED: user delete";
  		else {
  			cfgTree.getElementBy("sub_Security").childAdd("tbl").setAttr("id","Security_user").childAdd("fld").setAttr("NAME",nNm+"_cfg");
  			cfgTree.save(0x20, configPath);
  			SYS.cntrReq(SYS.XMLNode("scan").setAttr("path","/%2fgen%2fconfig"));		//Reload config command
  			if(!SYS.nodeAt(nAddr+"_cfg")) testREZ = "FAILED: load user from config";
  		}
  	}
  	//Group
  	nAddr = "/Security/grp_"+nNm;
  	if(testREZ == "PASSED" && (SYS.cntrReq(SYS.XMLNode("add").setAttr("path","/Security/%2fbr%2fgrp_").setText(nNm)) != 0 || !(node=SYS.nodeAt(nAddr)))) testREZ = "FAILED: group add";
  	else if(SYS.cntrReq(SYS.XMLNode("set").setAttr("path",nAddr+"/%2fprm%2fdscr").setText("Test")) != 0 || node.cfg("DESCR") != "Test") testREZ = "FAILED: change group";
  	else if(SYS.cntrReq(SYS.XMLNode("save").setAttr("path",nAddr+"/%2fobj")) != 0) testREZ = "FAILED: save group";
  	else if(SYS.cntrReq(SYS.XMLNode("set").setAttr("path",nAddr+"/%2fprm%2fdscr").setText("Test 1")) != 0 || 
  		SYS.cntrReq(SYS.XMLNode("load").setAttr("path",nAddr+"/%2fobj")) != 0 || node.cfg("DESCR") != "Test") testREZ = "FAILED: load group";
  	else {
  		node = false;
  		if(SYS.cntrReq(SYS.XMLNode("del").setAttr("path","/Security/%2fbr%2fgrp_").setText(nNm)) != 0 || SYS.nodeAt(nAddr)) testREZ = "FAILED: group delete";
  		else {
  			cfgTree.getElementBy("sub_Security").childAdd("tbl").setAttr("id","Security_grp").childAdd("fld").setAttr("NAME",nNm+"_cfg").setAttr("USERS",nNm+"_cfg");
  			cfgTree.save(0x20, configPath);
  			SYS.cntrReq(SYS.XMLNode("scan").setAttr("path","/%2fgen%2fconfig"));		//Reload config command
  			if(!SYS.nodeAt(nAddr+"_cfg")) testREZ = "FAILED: load group from config";
  		}
  	}
  	rez += "<tr><td>Security: User/Group create/remove, change, load, save and load from config</td><td>"+testREZ+"</td></tr>\n";
  }

  //**********************************
  //Transport subsystem tests
  if(sub < 0 || sub == 2) {
  	nList = SYS.Transport.nodeList("mod_");
  	cfgTree.getElementBy("sub_Transport").childAdd("tbl").setAttr("id","Transport_in");
  	cfgTree.getElementBy("sub_Transport").childAdd("tbl").setAttr("id","Transport_out");
  	for(i_n = 0; i_n < nList.length; i_n++) {
  		testREZ = "PASSED";
  		//Input transport
  		nAddr = "/Transport/"+nList[i_n]+"/in_"+nNm;
  		if(SYS.cntrReq(SYS.XMLNode("add").setAttr("path","/Transport/"+nList[i_n]+"/%2fbr%2fin_").setAttr("id",nNm)) != 0 || !(node=SYS.nodeAt(nAddr))) testREZ = "FAILED: input add";
  		else if(SYS.cntrReq(SYS.XMLNode("set").setAttr("path",nAddr+"/%2fprm%2fcfg%2fdscr").setText("Test")) != 0 || node.cfg("DESCRIPT") != "Test") testREZ = "FAILED: change input";
  		else if(SYS.cntrReq(SYS.XMLNode("save").setAttr("path",nAddr+"/%2fobj")) != 0) testREZ = "FAILED: save input";
  		else if(SYS.cntrReq(SYS.XMLNode("set").setAttr("path",nAddr+"/%2fprm%2fcfg%2fdscr").setText("Test 1")) != 0 || 
  			SYS.cntrReq(SYS.XMLNode("load").setAttr("path",nAddr+"/%2fobj")) != 0 || node.cfg("DESCRIPT") != "Test") testREZ = "FAILED: load input";
  		else {
  			node = false;
  			if(SYS.cntrReq(SYS.XMLNode("del").setAttr("path","/Transport/"+nList[i_n]+"/%2fbr%2fin_").setAttr("id",nNm)) != 0 || SYS.nodeAt(nAddr)) testREZ = "FAILED: input delete";
  			else {
  				cfgTree.getElementBy("Transport_in").childAdd("fld").setAttr("ID",nNm+"_cfg").setAttr("MODULE",nList[i_n].slice(4));
  				cfgTree.save(0x20, configPath);
  				SYS.cntrReq(SYS.XMLNode("scan").setAttr("path","/%2fgen%2fconfig"));		//Reload config command
  				if(!SYS.nodeAt(nAddr+"_cfg")) testREZ = "FAILED: load input from config";
  			}
  		}
  		//Output transport
  		nAddr = "/Transport/"+nList[i_n]+"/out_"+nNm;
  		if(testREZ == "PASSED" && (SYS.cntrReq(SYS.XMLNode("add").setAttr("path","/Transport/"+nList[i_n]+"/%2fbr%2fout_").setAttr("id",nNm)) != 0 || !(node=SYS.nodeAt(nAddr)))) testREZ = "FAILED: output add";
  		else if(SYS.cntrReq(SYS.XMLNode("set").setAttr("path",nAddr+"/%2fprm%2fcfg%2fdscr").setText("Test")) != 0 || node.cfg("DESCRIPT") != "Test") testREZ = "FAILED: change output";
  		else if(SYS.cntrReq(SYS.XMLNode("save").setAttr("path",nAddr+"/%2fobj")) != 0) testREZ = "FAILED: save output";
  		else if(SYS.cntrReq(SYS.XMLNode("set").setAttr("path",nAddr+"/%2fprm%2fcfg%2fdscr").setText("Test 1")) != 0 || 
  			SYS.cntrReq(SYS.XMLNode("load").setAttr("path",nAddr+"/%2fobj")) != 0 || node.cfg("DESCRIPT") != "Test") testREZ = "FAILED: load output";
  		else {
  			node = false;
  			if(SYS.cntrReq(SYS.XMLNode("del").setAttr("path","/Transport/"+nList[i_n]+"/%2fbr%2fout_").setAttr("id",nNm)) != 0 || SYS.nodeAt(nAddr)) testREZ = "FAILED: output delete";
  			else {
  				cfgTree.getElementBy("Transport_out").childAdd("fld").setAttr("ID",nNm+"_cfg").setAttr("MODULE",nList[i_n].slice(4));
  				cfgTree.save(0x20, configPath);
  				SYS.cntrReq(SYS.XMLNode("scan").setAttr("path","/%2fgen%2fconfig"));		//Reload config command
  				if(!SYS.nodeAt(nAddr+"_cfg")) testREZ = "FAILED: load output from config";
  			}
  		}
  		rez += "<tr><td>Transport."+nList[i_n].slice(4)+": Input/Output create/remove, change, load, save and load from config</td><td>"+testREZ+"</td></tr>\n";

  		//Disconnect/Connect module
  		req = SYS.XMLNode("get").setAttr("path","/Transport/"+nList[i_n]+"/%2fhelp%2fm_inf%2fSource");
  		SYS.cntrReq(req);
  		testREZ = SYS.Special.SystemTests.SOAttach(req.text(),0);
  		testREZ += "/"+SYS.Special.SystemTests.SOAttach(req.text(),0);
  		rez += "<tr><td>Transport."+nList[i_n].slice(4)+": Disconnect/Connect</td><td>"+testREZ+"</td></tr>\n";
  	}
  }

  //**********************************
  //Archive subsystem tests
  if(sub < 0 || sub == 3) {
  	testREZ = SYS.Special.SystemTests.ValBuf();
  	rez += "<tr><td>Archive: Tests of the values' buffer.</td><td>"+testREZ+"</td></tr>\n";

  	// Value archive
  	testREZ = "PASSED";
  	nAddr = "/Archive/va_"+nNm;
  	if(SYS.cntrReq(SYS.XMLNode("add").setAttr("path","/Archive/%2fbr%2fva_").setAttr("id",nNm)) != 0 || !(node=SYS.nodeAt(nAddr))) testREZ = "FAILED: add";
  	else if(SYS.cntrReq(SYS.XMLNode("set").setAttr("path",nAddr+"/%2fprm%2fcfg%2fdscr").setText("Test")) != 0 || node.cfg("DESCR") != "Test") testREZ = "FAILED: change";
  	else if(SYS.cntrReq(SYS.XMLNode("save").setAttr("path",nAddr+"/%2fobj")) != 0) testREZ = "FAILED: save";
  	else if(SYS.cntrReq(SYS.XMLNode("set").setAttr("path",nAddr+"/%2fprm%2fcfg%2fdscr").setText("Test 1")) != 0 || 
  		SYS.cntrReq(SYS.XMLNode("load").setAttr("path",nAddr+"/%2fobj")) != 0 || node.cfg("DESCR") != "Test") testREZ = "FAILED: load";
  	else {
  		node = false;
  		if(SYS.cntrReq(SYS.XMLNode("del").setAttr("path","/Archive/%2fbr%2fva_").setAttr("id",nNm)) != 0 || SYS.nodeAt(nAddr)) testREZ = "FAILED: delete";
  		else {
  			cfgTree.getElementBy("sub_Archive").childAdd("tbl").setAttr("id","Archive_val").childAdd("fld").setAttr("ID",nNm+"_cfg");
  			cfgTree.save(0x20, configPath);
  			SYS.cntrReq(SYS.XMLNode("scan").setAttr("path","/%2fgen%2fconfig"));		//Reload config command
  			if(!SYS.nodeAt(nAddr+"_cfg")) testREZ = "FAILED: load from config";
  		}
  	}
  	rez += "<tr><td>Archive: Value archive create/remove, change, load, save and load from config</td><td>"+testREZ+"</td></tr>\n";

  	// Archivators
  	nList = SYS.Archive.nodeList("mod_");
  	cfgTree.getElementBy("sub_Archive").childAdd("tbl").setAttr("id","Archive_mess_proc");
  	cfgTree.getElementBy("sub_Archive").childAdd("tbl").setAttr("id","Archive_val_proc");
  	for(i_n = 0; i_n < nList.length; i_n++) {
  		testREZ = "PASSED";
  		//Messages archivator
  		nAddr = "/Archive/"+nList[i_n]+"/mess_"+nNm;
  		if(SYS.cntrReq(SYS.XMLNode("add").setAttr("path","/Archive/"+nList[i_n]+"/%2fbr%2fmess_").setAttr("id",nNm)) != 0 || !(node=SYS.nodeAt(nAddr))) testREZ = "FAILED: messages add";
  		else if(SYS.cntrReq(SYS.XMLNode("set").setAttr("path",nAddr+"/%2fprm%2fcfg%2fdscr").setText("Test")) != 0 || node.cfg("DESCR") != "Test") testREZ = "FAILED: change messages";
  		else if(SYS.cntrReq(SYS.XMLNode("save").setAttr("path",nAddr+"/%2fobj")) != 0) testREZ = "FAILED: save messages";
  		else if(SYS.cntrReq(SYS.XMLNode("set").setAttr("path",nAddr+"/%2fprm%2fcfg%2fdscr").setText("Test 1")) != 0 || 
  			SYS.cntrReq(SYS.XMLNode("load").setAttr("path",nAddr+"/%2fobj")) != 0 || node.cfg("DESCR") != "Test") testREZ = "FAILED: load messages";
  		else {
  			node = false;
  			if(SYS.cntrReq(SYS.XMLNode("del").setAttr("path","/Archive/"+nList[i_n]+"/%2fbr%2fmess_").setAttr("id",nNm)) != 0 || SYS.nodeAt(nAddr)) testREZ = "FAILED: messages delete";
  			else {
  				cfgTree.getElementBy("Archive_mess_proc").childAdd("fld").setAttr("ID",nNm+"_cfg").setAttr("MODUL",nList[i_n].slice(4));
  				cfgTree.save(0x20, configPath);
  				SYS.cntrReq(SYS.XMLNode("scan").setAttr("path","/%2fgen%2fconfig"));		//Reload config command
  				if(!SYS.nodeAt(nAddr+"_cfg")) testREZ = "FAILED: load messages from config";
  			}
  		}
  		//Value archivator
  		nAddr = "/Archive/"+nList[i_n]+"/val_"+nNm;
  		if(testREZ == "PASSED" && (SYS.cntrReq(SYS.XMLNode("add").setAttr("path","/Archive/"+nList[i_n]+"/%2fbr%2fval_").setAttr("id",nNm)) != 0 || !(node=SYS.nodeAt(nAddr)))) testREZ = "FAILED: values add";
  		else if(SYS.cntrReq(SYS.XMLNode("set").setAttr("path",nAddr+"/%2fprm%2fcfg%2fdscr").setText("Test")) != 0 || node.cfg("DESCR") != "Test") testREZ = "FAILED: change values";
  		else if(SYS.cntrReq(SYS.XMLNode("save").setAttr("path",nAddr+"/%2fobj")) != 0) testREZ = "FAILED: save values";
  		else if(SYS.cntrReq(SYS.XMLNode("set").setAttr("path",nAddr+"/%2fprm%2fcfg%2fdscr").setText("Test 1")) != 0 || 
  			SYS.cntrReq(SYS.XMLNode("load").setAttr("path",nAddr+"/%2fobj")) != 0 || node.cfg("DESCR") != "Test") testREZ = "FAILED: load values";
  		else {
  			node = false;
  			if(SYS.cntrReq(SYS.XMLNode("del").setAttr("path","/Archive/"+nList[i_n]+"/%2fbr%2fval_").setAttr("id",nNm)) != 0 || SYS.nodeAt(nAddr)) testREZ = "FAILED: values delete";
  			else {
  				cfgTree.getElementBy("Archive_val_proc").childAdd("fld").setAttr("ID",nNm+"_cfg").setAttr("MODUL",nList[i_n].slice(4));
  				cfgTree.save(0x20, configPath);
  				SYS.cntrReq(SYS.XMLNode("scan").setAttr("path","/%2fgen%2fconfig"));		//Reload config command
  				if(!SYS.nodeAt(nAddr+"_cfg")) testREZ = "FAILED: load values from config";
  			}
  		}
  		rez += "<tr><td>Archive."+nList[i_n].slice(4)+": Messages/Values create/remove, change, load, save and load from config</td><td>"+testREZ+"</td></tr>\n";

  		//Disconnect/Connect module
  		req = SYS.XMLNode("get").setAttr("path","/Archive/"+nList[i_n]+"/%2fhelp%2fm_inf%2fSource");
  		SYS.cntrReq(req);
  		testREZ = SYS.Special.SystemTests.SOAttach(req.text(),0);
  		testREZ += "/"+SYS.Special.SystemTests.SOAttach(req.text(),0);
  		rez += "<tr><td>Archive."+nList[i_n].slice(4)+": Disconnect/Connect</td><td>"+testREZ+"</td></tr>\n";
  	}
  }

  //**********************************
  //DB subsystem tests
  if(sub < 0 || sub == 4) {
  	nList = SYS.BD.nodeList("mod_");
  	for(i_n = 0; i_n < nList.length; i_n++) {
  		testREZ = "PASSED";
  		//Messages archivator
  		nAddr = "/BD/"+nList[i_n]+"/db_"+nNm;
  		if(SYS.cntrReq(SYS.XMLNode("add").setAttr("path","/BD/"+nList[i_n]+"/%2fbr%2fdb_").setAttr("id",nNm)) != 0 || !(node=SYS.nodeAt(nAddr))) testREZ = "FAILED: add";
  		else if(SYS.cntrReq(SYS.XMLNode("set").setAttr("path",nAddr+"/%2fprm%2fcfg%2fdscr").setText("Test")) != 0 || node.cfg("DESCR") != "Test") testREZ = "FAILED: change";
  		else if(SYS.cntrReq(SYS.XMLNode("save").setAttr("path",nAddr+"/%2fobj")) != 0) testREZ = "FAILED: save";
  		else if(SYS.cntrReq(SYS.XMLNode("set").setAttr("path",nAddr+"/%2fprm%2fcfg%2fdscr").setText("Test 1")) != 0 || 
  			SYS.cntrReq(SYS.XMLNode("load").setAttr("path",nAddr+"/%2fobj")) != 0 || node.cfg("DESCR") != "Test") testREZ = "FAILED: load";
  		else {
  			node = false;
  			if(SYS.cntrReq(SYS.XMLNode("del").setAttr("path","/BD/"+nList[i_n]+"/%2fbr%2fdb_").setAttr("id",nNm)) != 0 || SYS.nodeAt(nAddr)) testREZ = "FAILED: delete";
  			else {
  				cfgTree.getElementBy("DB").childAdd("fld").setAttr("ID",nNm+"_cfg").setAttr("TYPE",nList[i_n].slice(4)).setAttr("EN",0);
  				cfgTree.save(0x20, configPath);
  				SYS.cntrReq(SYS.XMLNode("scan").setAttr("path","/%2fgen%2fconfig"));		//Reload config command
  				if(!SYS.nodeAt(nAddr+"_cfg")) testREZ = "FAILED: load from config";
  			}
  		}
  		rez += "<tr><td>DB."+nList[i_n].slice(4)+": create/remove, change, load, save and load from config</td><td>"+testREZ+"</td></tr>\n";

  		//Disconnect/Connect module
  		req = SYS.XMLNode("get").setAttr("path","/BD/"+nList[i_n]+"/%2fhelp%2fm_inf%2fSource");
  		SYS.cntrReq(req);
  		testREZ = SYS.Special.SystemTests.SOAttach(req.text(),0);
  		testREZ += "/"+SYS.Special.SystemTests.SOAttach(req.text(),0);
  		rez += "<tr><td>DB."+nList[i_n].slice(4)+": Disconnect/Connect</td><td>"+testREZ+"</td></tr>\n";
  	}
  }

  //**********************************
  //Protocol subsystem tests
  if(sub < 0 || sub == 5) {
  	nList = SYS.Protocol.nodeList("mod_");
  	for(i_n = 0; i_n < nList.length; i_n++) {
  		//Disconnect/Connect module
  		req = SYS.XMLNode("get").setAttr("path","/Protocol/"+nList[i_n]+"/%2fhelp%2fm_inf%2fSource");
  		SYS.cntrReq(req);
  		testREZ = SYS.Special.SystemTests.SOAttach(req.text(),0);
  		testREZ += "/"+SYS.Special.SystemTests.SOAttach(req.text(),0);
  		rez += "<tr><td>Protocol."+nList[i_n].slice(4)+": Disconnect/Connect</td><td>"+testREZ+"</td></tr>\n";
  	}
  }

  //**********************************
  //DAQ subsystem tests
  if(sub < 0 || sub == 6) {
  	// Templates
  	testREZ = "PASSED";
  	nAddr = "/DAQ/tmplb_"+nNm;
  	if(SYS.cntrReq(SYS.XMLNode("add").setAttr("path","/DAQ/%2fbr%2ftmplb_").setAttr("id",nNm)) != 0 || !(node=SYS.nodeAt(nAddr))) testREZ = "FAILED: template library add";
  	else if(SYS.cntrReq(SYS.XMLNode("set").setAttr("path",nAddr+"/%2flib%2fcfg%2fdescr").setText("Test")) != 0 || node.cfg("DESCR") != "Test") testREZ = "FAILED: change template library";
  	else if(SYS.cntrReq(SYS.XMLNode("save").setAttr("path",nAddr+"/%2fobj")) != 0) testREZ = "FAILED: save template library";
  	else if(SYS.cntrReq(SYS.XMLNode("set").setAttr("path",nAddr+"/%2flib%2fcfg%2fdescr").setText("Test 1")) != 0 || 
  		SYS.cntrReq(SYS.XMLNode("load").setAttr("path",nAddr+"/%2fobj")) != 0 || node.cfg("DESCR") != "Test") testREZ = "FAILED: load template library";
  	else {
  		node = false;

  		// Template
  		nAddrLb = nAddr+"/tmpl_"+nNm;
  		if(SYS.cntrReq(SYS.XMLNode("add").setAttr("path",nAddr+"/%2fbr%2ftmpl_").setAttr("id",nNm)) != 0 || !(node=SYS.nodeAt(nAddrLb))) testREZ = "FAILED: template add";
  		else if(SYS.cntrReq(SYS.XMLNode("set").setAttr("path",nAddrLb+"/%2ftmpl%2fcfg%2fdescr").setText("Test")) != 0 || node.cfg("DESCR") != "Test") testREZ = "FAILED: change template";
  		else if(SYS.cntrReq(SYS.XMLNode("save").setAttr("path",nAddrLb+"/%2fobj")) != 0) testREZ = "FAILED: save template";
  		else if(SYS.cntrReq(SYS.XMLNode("set").setAttr("path",nAddrLb+"/%2ftmpl%2fcfg%2fdescr").setText("Test 1")) != 0 || 
  			SYS.cntrReq(SYS.XMLNode("load").setAttr("path",nAddrLb+"/%2fobj")) != 0 || node.cfg("DESCR") != "Test") testREZ = "FAILED: load template";
  		node = false;

  		if(SYS.cntrReq(SYS.XMLNode("del").setAttr("path","/DAQ/%2fbr%2ftmplb_").setAttr("id",nNm)) != 0 || SYS.nodeAt(nAddr)) testREZ = "FAILED: template library delete";
  		else {
  			cfgTree.getElementBy("sub_DAQ").childAdd("tbl").setAttr("id","tmplib").childAdd("fld").setAttr("ID",nNm+"_cfg").setAttr("DB","tmplib_"+nNm+"_cfg");
  			cfgTree.getElementBy("sub_DAQ").childAdd("tbl").setAttr("id","tmplib_"+nNm+"_cfg").childAdd("fld").setAttr("ID",nNm+"_cfg");
  			cfgTree.save(0x20, configPath);
  			SYS.cntrReq(SYS.XMLNode("scan").setAttr("path","/%2fgen%2fconfig"));		//Reload config command
  			if(!SYS.nodeAt(nAddr+"_cfg") || !SYS.nodeAt(nAddr+"_cfg/tmpl_"+nNm+"_cfg")) testREZ = "FAILED: load template library from config";
  		}
  	}
  	rez += "<tr><td>DAQ: Templates library create/remove, change, load, save and load from config</td><td>"+testREZ+"</td></tr>\n";

  	// Modules
  	nList = SYS.DAQ.nodeList("mod_");
  	for(i_n = 0; i_n < nList.length; i_n++) {
  		testREZ = "PASSED";
  		testREZ_ = "PASSED";
  		//> Controller
  		nAddr = "/DAQ/"+nList[i_n]+"/cntr_"+nNm;
  		if(SYS.cntrReq(SYS.XMLNode("add").setAttr("path","/DAQ/"+nList[i_n]+"/%2fbr%2fcntr_").setAttr("id",nNm)) != 0 || !(node=SYS.nodeAt(nAddr))) testREZ = "FAILED: controller add";
  		else if(SYS.cntrReq(SYS.XMLNode("set").setAttr("path",nAddr+"/%2fcntr%2fcfg%2fDESCR").setText("Test")) != 0 || node.cfg("DESCR") != "Test") testREZ = "FAILED: controller change";
  		else if(SYS.cntrReq(SYS.XMLNode("save").setAttr("path",nAddr+"/%2fobj")) != 0) testREZ = "FAILED: controller save";
  		else if(SYS.cntrReq(SYS.XMLNode("set").setAttr("path",nAddr+"/%2fcntr%2fcfg%2fDESCR").setText("Test 1")) != 0 || 
  			SYS.cntrReq(SYS.XMLNode("load").setAttr("path",nAddr+"/%2fobj")) != 0 || node.cfg("DESCR") != "Test") testREZ = "FAILED: controller load";
  		else {
  			node = false;

  			// Parameter
  			if(nList[i_n] != "mod_DAQGate") {
  				nAddr1 = nAddr+"/prm_"+nNm;
  				if(SYS.cntrReq(SYS.XMLNode("add").setAttr("path",nAddr+"/%2fbr%2fprm_").setAttr("id",nNm)) != 0 || !(node=SYS.nodeAt(nAddr1))) testREZ = "FAILED: parameter add";
  				else if(SYS.cntrReq(SYS.XMLNode("set").setAttr("path",nAddr1+"/%2fprm%2fcfg%2fDESCR").setText("Test")) != 0 || node.cfg("DESCR") != "Test") testREZ = "FAILED: parameter change";
  				else if(SYS.cntrReq(SYS.XMLNode("save").setAttr("path",nAddr1+"/%2fobj")) != 0) testREZ = "FAILED: parameter save";
  				else if(SYS.cntrReq(SYS.XMLNode("set").setAttr("path",nAddr1+"/%2fprm%2fcfg%2fDESCR").setText("Test 1")) != 0 || 
  					SYS.cntrReq(SYS.XMLNode("load").setAttr("path",nAddr1+"/%2fobj")) != 0 || node.cfg("DESCR") != "Test") testREZ = "FAILED: parameter load";
  				node = false;
  			}

  			if(nList[i_n] == "mod_BlockCalc") {
  				nAddr1 = nAddr+"/blk_"+nNm;
  				if(SYS.cntrReq(SYS.XMLNode("add").setAttr("path",nAddr+"/%2fbr%2fblk_").setAttr("id",nNm)) != 0 || !(node=SYS.nodeAt(nAddr1))) testREZ_ = "FAILED: block add";
  				else if(SYS.cntrReq(SYS.XMLNode("set").setAttr("path",nAddr1+"/%2fblck%2fcfg%2fdescr").setText("Test")) != 0 || node.cfg("DESCR") != "Test") testREZ_ = "FAILED: block change";
  				else if(SYS.cntrReq(SYS.XMLNode("save").setAttr("path",nAddr1+"/%2fobj")) != 0) testREZ_ = "FAILED: block save";
  				else if(SYS.cntrReq(SYS.XMLNode("set").setAttr("path",nAddr1+"/%2fblck%2fcfg%2fdescr").setText("Test 1")) != 0 || 
  					SYS.cntrReq(SYS.XMLNode("load").setAttr("path",nAddr1+"/%2fobj")) != 0 || node.cfg("DESCR") != "Test") testREZ_ = "FAILED: block load";
  				node = false;
  			}
  			if(nList[i_n] == "mod_JavaLikeCalc") {
  				nAddr_ = "/DAQ/"+nList[i_n]+"/lib_"+nNm;
  				if(SYS.cntrReq(SYS.XMLNode("add").setAttr("path","/DAQ/"+nList[i_n]+"/%2fbr%2flib_").setAttr("id",nNm)) != 0 || !(node=SYS.nodeAt(nAddr_))) testREZ_ = "FAILED: library add";
  				else if(SYS.cntrReq(SYS.XMLNode("set").setAttr("path",nAddr_+"/%2flib%2fcfg%2fdescr").setText("Test")) != 0 || node.cfg("DESCR") != "Test") testREZ_ = "FAILED: library change";
  				else if(SYS.cntrReq(SYS.XMLNode("save").setAttr("path",nAddr_+"/%2fobj")) != 0) testREZ_ = "FAILED: library save";
  				else if(SYS.cntrReq(SYS.XMLNode("set").setAttr("path",nAddr_+"/%2flib%2fcfg%2fdescr").setText("Test 1")) != 0 || 
  					SYS.cntrReq(SYS.XMLNode("load").setAttr("path",nAddr_+"/%2fobj")) != 0 || node.cfg("DESCR") != "Test") testREZ_ = "FAILED: library load";
  				else {
  					node = false;

  					// Function
  					nAddr_1 = nAddr_+"/fnc_"+nNm;
  					if(SYS.cntrReq(SYS.XMLNode("add").setAttr("path",nAddr_+"/%2fbr%2ffnc_").setAttr("id",nNm)) != 0 || !(node=SYS.nodeAt(nAddr_1))) testREZ_ = "FAILED: function add";
  					else if(SYS.cntrReq(SYS.XMLNode("set").setAttr("path",nAddr_1+"/%2ffunc%2fcfg%2fdescr").setText("Test")) != 0 || node.cfg("DESCR") != "Test") testREZ_ = "FAILED: function change";
  					else if(SYS.cntrReq(SYS.XMLNode("save").setAttr("path",nAddr_1+"/%2fobj")) != 0) testREZ_ = "FAILED: function save";
  					else if(SYS.cntrReq(SYS.XMLNode("set").setAttr("path",nAddr_1+"/%2ffunc%2fcfg%2fdescr").setText("Test 1")) != 0 || 
  						SYS.cntrReq(SYS.XMLNode("load").setAttr("path",nAddr_1+"/%2fobj")) != 0 || node.cfg("DESCR") != "Test") testREZ_ = "FAILED: function load";
  					node = false;
  					if(SYS.cntrReq(SYS.XMLNode("del").setAttr("path","/DAQ/"+nList[i_n]+"/%2fbr%2flib_").setAttr("id",nNm)) != 0 || SYS.nodeAt(nAddr_)) testREZ_ = "FAILED: function delete";
  				}			
  			}

  			if(SYS.cntrReq(SYS.XMLNode("del").setAttr("path","/DAQ/"+nList[i_n]+"/%2fbr%2fcntr_").setAttr("id",nNm)) != 0 || SYS.nodeAt(nAddr)) testREZ = "FAILED: controller delete";
  			else {
  				treeNd = cfgTree.getElementBy("sub_DAQ");
  				if(!treeNd.getElementBy(nList[i_n])) treeNd.childAdd("node").setAttr("id",nList[i_n]);
  				treeNd = treeNd.getElementBy(nList[i_n]);

  				treeNd_t = treeNd.childAdd("tbl").setAttr("id","DAQ").childAdd("fld").setAttr("ID",nNm+"_cfg").setAttr("PRM_BD",nNm+"_cfg_prm").setAttr("ENABLE",1);
  				if(nList[i_n] == "mod_JavaLikeCalc") treeNd_t.setAttr("FUNC","servProc.fnc_crc16");
  				treeNd.childAdd("tbl").setAttr("id",nNm+"_cfg_prm").childAdd("fld").setAttr("SHIFR",nNm+"_cfg");
  				if(nList[i_n] == "mod_BlockCalc") {
  					treeNd_t.setAttr("BLOCK_SH",nNm+"_cfg_blcks");
  					treeNd.childAdd("tbl").setAttr("id",nNm+"_cfg_blcks").childAdd("fld").setAttr("ID",nNm+"_cfg");
  				}
  				if(nList[i_n] == "mod_JavaLikeCalc") {
  					treeNd.childAdd("tbl").setAttr("id","lib").childAdd("fld").setAttr("ID",nNm+"_cfg").setAttr("DB","lib_"+nNm+"_cfg");
  					treeNd.childAdd("tbl").setAttr("id","lib_"+nNm+"_cfg").childAdd("fld").setAttr("ID",nNm+"_cfg");
  				}

  				cfgTree.save(0x20, configPath);
  				SYS.cntrReq(SYS.XMLNode("scan").setAttr("path","/%2fgen%2fconfig"));		//Reload config command
  				SYS.nodeAt(nAddr+"_cfg").enable(true);
  				if(!SYS.nodeAt(nAddr+"_cfg")) testREZ = "FAILED: load controller from config";
  				else {
  					if(!SYS.nodeAt(nAddr+"_cfg/prm_"+nNm+"_cfg")) testREZ = "FAILED: load parameter from config";
  					if(nList[i_n] == "mod_BlockCalc" && !SYS.nodeAt(nAddr+"_cfg/blk_"+nNm+"_cfg")) testREZ_ = "FAILED: load block from config";
  					if(nList[i_n] == "mod_JavaLikeCalc") {
  						if(!SYS.nodeAt(nAddr_+"_cfg")) testREZ_ = "FAILED: load library from config";
  						else if(!SYS.nodeAt(nAddr_+"_cfg/fnc_"+nNm+"_cfg")) testREZ_ = "FAILED: load function from config";
  					}
  				}
  			}
  		}
  		rez += "<tr><td>DAQ."+nList[i_n].slice(4)+": create/remove, change, load, save and load from config</td><td>"+testREZ+"</td></tr>\n";
  		if(nList[i_n] == "mod_BlockCalc")
  			rez += "<tr><td>DAQ."+nList[i_n].slice(4)+": Blocks create/remove, change, load, save and load from config</td><td>"+testREZ_+"</td></tr>\n";
  		else if(nList[i_n] == "mod_JavaLikeCalc")
  			rez += "<tr><td>DAQ."+nList[i_n].slice(4)+": Functions and its libraries create/remove, change, load, save and load from config</td><td>"+testREZ_+"</td></tr>\n";

  		//Disconnect/Connect module
  		if(nList[i_n] != "mod_JavaLikeCalc") {
  			req = SYS.XMLNode("get").setAttr("path","/DAQ/"+nList[i_n]+"/%2fhelp%2fm_inf%2fSource");
  			SYS.cntrReq(req);
  			testREZ = SYS.Special.SystemTests.SOAttach(req.text(),0);
  			testREZ += "/"+SYS.Special.SystemTests.SOAttach(req.text(),0);
  			rez += "<tr><td>DAQ."+nList[i_n].slice(4)+": Disconnect/Connect</td><td>"+testREZ+"</td></tr>\n";
  		}
  	}
  }

  //**********************************
  //UI subsystem tests
  if(sub < 0 || sub == 7) {
  	nList = SYS.UI.nodeList("mod_");
  	for(i_n = 0; i_n < nList.length; i_n++) {
  		if(nList[i_n] == "mod_QTStarter" || nList[i_n] == "mod_QTCfg") continue;

  		//UI.VCAEngine tests
  		if(nList[i_n] == "mod_VCAEngine") {
  			// Widgets library
  			testREZ = "PASSED";
  			nAddr = "/UI/"+nList[i_n]+"/wlb_"+nNm;
  			if(SYS.cntrReq(SYS.XMLNode("add").setAttr("path","/UI/"+nList[i_n]+"/%2fbr%2fwlb_").setAttr("id",nNm)) || !(node=SYS.nodeAt(nAddr))) testREZ = "FAILED: widgets library add";
  			else if(SYS.cntrReq(SYS.XMLNode("set").setAttr("path",nAddr+"/%2fobj%2fcfg%2fdescr").setText("Test")) || 
  				SYS.cntrReq(req=SYS.XMLNode("get").setAttr("path",nAddr+"/%2fobj%2fcfg%2fdescr")) || req.text() != "Test") testREZ = "FAILED: change widgets library";
  			else if(SYS.cntrReq(SYS.XMLNode("save").setAttr("path",nAddr+"/%2fobj"))) testREZ = "FAILED: save widgets library";
  			else if(SYS.cntrReq(SYS.XMLNode("set").setAttr("path",nAddr+"/%2fobj%2fcfg%2fdescr").setText("Test 1")) || 
  				SYS.cntrReq(SYS.XMLNode("load").setAttr("path",nAddr+"/%2fobj")) || SYS.cntrReq(req=SYS.XMLNode("get").setAttr("path",nAddr+"/%2fobj%2fcfg%2fdescr")) ||
  				req.text() != "Test") testREZ = "FAILED: load widgets library";
  			else {
  				node = false;

  				// Widget
  				nAddr1 = nAddr+"/wdg_"+nNm;
  				if(SYS.cntrReq(SYS.XMLNode("add").setAttr("path",nAddr+"/%2fbr%2fwdg_").setAttr("id",nNm)) || !(node=SYS.nodeAt(nAddr1))) testREZ = "FAILED: widget add";
  				else if(SYS.cntrReq(SYS.XMLNode("set").setAttr("path",nAddr1+"/%2fwdg%2fcfg%2fdescr").setText("Test")) || 
  					SYS.cntrReq(req=SYS.XMLNode("get").setAttr("path",nAddr1+"/%2fwdg%2fcfg%2fdescr")) || req.text() != "Test") testREZ = "FAILED: change widget";
  				else if(SYS.cntrReq(SYS.XMLNode("save").setAttr("path",nAddr1+"/%2fobj"))) testREZ = "FAILED: save widget";
  				else if(SYS.cntrReq(SYS.XMLNode("set").setAttr("path",nAddr1+"/%2fwdg%2fcfg%2fdescr").setText("Test 1")) || 
  					SYS.cntrReq(SYS.XMLNode("load").setAttr("path",nAddr1+"/%2fobj")) || SYS.cntrReq(req=SYS.XMLNode("get").setAttr("path",nAddr1+"/%2fwdg%2fcfg%2fdescr")) ||
  						req.text() != "Test") testREZ = "FAILED: load widget";
  				node = false;

  				if(SYS.cntrReq(SYS.XMLNode("del").setAttr("path","/UI/"+nList[i_n]+"/%2fbr%2fwlb_").setAttr("id",nNm)) != 0 || SYS.nodeAt(nAddr)) testREZ = "FAILED: widgets library delete";
  				else {
  					cfgTree.getElementBy("mod_VCAEngine").childAdd("tbl").setAttr("id","LIB").childAdd("fld").setAttr("ID",nNm+"_cfg").setAttr("DB_TBL","wlib_"+nNm+"_cfg");
  					cfgTree.getElementBy("mod_VCAEngine").childAdd("tbl").setAttr("id","wlib_"+nNm+"_cfg").childAdd("fld").setAttr("ID",nNm+"_cfg").setAttr("PARENT","/wlb_originals/wdg_Box");
  					cfgTree.save(0x20, configPath);
  					SYS.cntrReq(SYS.XMLNode("scan").setAttr("path","/%2fgen%2fconfig"));		//Reload config command
  					if(!SYS.nodeAt(nAddr+"_cfg") || !SYS.nodeAt(nAddr+"_cfg/wdg_"+nNm+"_cfg")) testREZ = "FAILED: load widgets library from config";
  				}
  			}
  			rez += "<tr><td>UI.VCAEngine: Widgets and widgets' library create/remove, change, load, save and load from config</td><td>"+testREZ+"</td></tr>\n";

  			// Project
  			testREZ = "PASSED";
  			nAddr = "/UI/"+nList[i_n]+"/prj_"+nNm;
  			if(SYS.cntrReq(SYS.XMLNode("add").setAttr("path","/UI/"+nList[i_n]+"/%2fbr%2fprj_").setAttr("id",nNm)) || !(node=SYS.nodeAt(nAddr))) testREZ = "FAILED: project add";
  			else if(SYS.cntrReq(SYS.XMLNode("set").setAttr("path",nAddr+"/%2fobj%2fcfg%2fdescr").setText("Test"))  || 
  				SYS.cntrReq(req=SYS.XMLNode("get").setAttr("path",nAddr+"/%2fobj%2fcfg%2fdescr")) || req.text() != "Test") testREZ = "FAILED: change project";
  			else if(SYS.cntrReq(SYS.XMLNode("save").setAttr("path",nAddr+"/%2fobj")) != 0) testREZ = "FAILED: save project";
  			else if(SYS.cntrReq(SYS.XMLNode("set").setAttr("path",nAddr+"/%2fobj%2fcfg%2fdescr").setText("Test 1")) != 0 || 
  				SYS.cntrReq(SYS.XMLNode("load").setAttr("path",nAddr+"/%2fobj")) != 0 || SYS.cntrReq(req=SYS.XMLNode("get").setAttr("path",nAddr+"/%2fobj%2fcfg%2fdescr")) ||
  				req.text() != "Test") testREZ = "FAILED: load project";
  			else {
  				node = false;

  				// Page
  				nAddr1 = nAddr+"/pg_"+nNm;
  				if(SYS.cntrReq(SYS.XMLNode("add").setAttr("path",nAddr+"/%2fbr%2fpg_").setAttr("id",nNm)) != 0 || !(node=SYS.nodeAt(nAddr1))) testREZ = "FAILED: page add";
  				else if(SYS.cntrReq(SYS.XMLNode("set").setAttr("path",nAddr1+"/%2fwdg%2fst%2fparent").setText("/wlb_originals/wdg_Box")) != 0) testREZ = "FAILED: change page";
  				else if(SYS.cntrReq(SYS.XMLNode("set").setAttr("path",nAddr1+"/%2fwdg%2fst%2fen").setText(1)) != 0) testREZ = "FAILED: change page";
  				else if(SYS.cntrReq(SYS.XMLNode("set").setAttr("path",nAddr1+"/%2fwdg%2fcfg%2fdescr").setText("Test")) != 0 || 
  						SYS.cntrReq(req=SYS.XMLNode("get").setAttr("path",nAddr1+"/%2fwdg%2fcfg%2fdescr")) || req.text() != "Test") testREZ = "FAILED: change page";
  				else if(SYS.cntrReq(SYS.XMLNode("save").setAttr("path",nAddr1+"/%2fobj")) != 0) testREZ = "FAILED: save page";
  				else if(SYS.cntrReq(SYS.XMLNode("set").setAttr("path",nAddr1+"/%2fwdg%2fcfg%2fdescr").setText("Test 1")) != 0 || 
  						SYS.cntrReq(SYS.XMLNode("load").setAttr("path",nAddr1+"/%2fobj")) != 0 || SYS.cntrReq(req=SYS.XMLNode("get").setAttr("path",nAddr1+"/%2fwdg%2fcfg%2fdescr")) ||
  					req.text() != "Test") testREZ = "FAILED: load page";

  				nAddr2 = nAddr1+"/wdg_"+nNm;
  				if(SYS.cntrReq(SYS.XMLNode("add").setAttr("path",nAddr1+"/%2fbr%2fwdg_").setAttr("id",nNm)) != 0 || !(node=SYS.nodeAt(nAddr2))) testREZ = "FAILED: widget add";
  				else if(SYS.cntrReq(SYS.XMLNode("set").setAttr("path",nAddr2+"/%2fwdg%2fcfg%2fdescr").setText("Test")) != 0 || 
  						SYS.cntrReq(req=SYS.XMLNode("get").setAttr("path",nAddr2+"/%2fwdg%2fcfg%2fdescr")) || req.text() != "Test") testREZ = "FAILED: change widget";
  				else if(SYS.cntrReq(SYS.XMLNode("save").setAttr("path",nAddr2+"/%2fobj")) != 0) testREZ = "FAILED: save widget";
  				else if(SYS.cntrReq(SYS.XMLNode("set").setAttr("path",nAddr2+"/%2fwdg%2fcfg%2fdescr").setText("Test 1")) != 0 || 
  						SYS.cntrReq(SYS.XMLNode("load").setAttr("path",nAddr2+"/%2fobj")) != 0 || SYS.cntrReq(req=SYS.XMLNode("get").setAttr("path",nAddr2+"/%2fwdg%2fcfg%2fdescr")) ||
  					req.text() != "Test") testREZ = "FAILED: load widget";
  				node = false;

  				if(SYS.cntrReq(SYS.XMLNode("del").setAttr("path","/UI/"+nList[i_n]+"/%2fbr%2fprj_").setAttr("id",nNm)) != 0 || SYS.nodeAt(nAddr)) testREZ = "FAILED: project delete";
  				else {
  					cfgTree.getElementBy("mod_VCAEngine").childAdd("tbl").setAttr("id","PRJ").childAdd("fld").setAttr("ID",nNm+"_cfg").setAttr("DB_TBL","prj_"+nNm+"_cfg");
  					cfgTree.getElementBy("mod_VCAEngine").childAdd("tbl").setAttr("id","prj_"+nNm+"_cfg").childAdd("fld").setAttr("OWNER","/"+nNm+"_cfg").setAttr("ID",nNm+"_cfg").setAttr("PARENT","/wlb_originals/wdg_Box");//.setAttr("FLGS",1);
  					cfgTree.getElementBy("mod_VCAEngine").childAdd("tbl").setAttr("id","prj_"+nNm+"_cfg_incl").childAdd("fld").setAttr("IDW","/prj_"+nNm+"_cfg/pg_"+nNm+"_cfg").setAttr("ID",nNm+"_cfg").setAttr("PARENT","/wlb_originals/wdg_Box");
  					cfgTree.save(0x20, configPath);
  					SYS.cntrReq(SYS.XMLNode("scan").setAttr("path","/%2fgen%2fconfig"));		//Reload config command
  					if(!SYS.nodeAt(nAddr+"_cfg"))	testREZ = "FAILED: load project from config";
  					else if(!SYS.nodeAt(nAddr+"_cfg/pg_"+nNm+"_cfg"))	testREZ = "FAILED: load page from config";
  					else if(!SYS.nodeAt(nAddr+"_cfg/pg_"+nNm+"_cfg/wdg_"+nNm+"_cfg"))	testREZ = "FAILED: load widget from config";
  				}
  			}
  			rez += "<tr><td>UI.VCAEngine: Project, pages and widgets create/remove, change, load, save and load from config</td><td>"+testREZ+"</td></tr>\n";

  			//Session
  			testREZ = "PASSED";
  			nAddr = "/UI/"+nList[i_n]+"/ses_"+nNm;
  			req = SYS.XMLNode("CntrReqs").setAttr("path","/UI/"+nList[i_n]);
  			req.childAdd("add").setAttr("path","/%2fbr%2fses_").setText(nNm);
  			req.childAdd("set").setAttr("path","/ses_"+nNm+"/%2fobj%2fst%2fprj").setText("tmplSO");
  			req.childAdd("set").setAttr("path","/ses_"+nNm+"/%2fobj%2fst%2fstart").setText(1);
  			if(SYS.cntrReq(req) != 0 || !SYS.nodeAt(nAddr)) testREZ = "FAILED: session add/start";
  			else if(SYS.cntrReq(req=SYS.XMLNode("del").setAttr("path","/UI/"+nList[i_n]+"/%2fbr%2fses_").setText(nNm)) || SYS.nodeAt(nAddr)) testREZ = "FAILED: session delete";
  			rez += "<tr><td>UI.VCAEngine: Session create, start and remove</td><td>"+testREZ+"</td></tr>\n";
  		}

  		//Disconnect/Connect module
  		req = SYS.XMLNode("get").setAttr("path","/UI/"+nList[i_n]+"/%2fhelp%2fm_inf%2fSource");
  		SYS.cntrReq(req);
  		testREZ = SYS.Special.SystemTests.SOAttach(req.text(),0);
  		testREZ += "/"+SYS.Special.SystemTests.SOAttach(req.text(),0);
  		rez += "<tr><td>UI."+nList[i_n].slice(4)+": Disconnect/Connect</td><td>"+testREZ+"</td></tr>\n";
  	}
  }

  //**********************************
  //Special subsystem tests
  if(sub < 0 || sub == 8) {
  	nList = SYS.Special.nodeList("mod_");
  	for(i_n = 0; i_n < nList.length; i_n++) {
  		if(nList[i_n] == "mod_SystemTests") continue;
  		//Disconnect/Connect module
  		req = SYS.XMLNode("get").setAttr("path","/Special/"+nList[i_n]+"/%2fhelp%2fm_inf%2fSource");
  		SYS.cntrReq(req);
  		testREZ = SYS.Special.SystemTests.SOAttach(req.text(),0);
  		testREZ += "/"+SYS.Special.SystemTests.SOAttach(req.text(),0);
  		rez += "<tr><td>Special."+nList[i_n].slice(4)+": Disconnect/Connect</td><td>"+testREZ+"</td></tr>\n";
  	}
  }

  //Restore original config file
  SYS.fileWrite(configPath,SYS.fileRead(configPath+".orig"));

  //Save result to file ReleaseTests.html
  SYS.fileWrite("ReleaseTests.html", "<?xml version='1.0' ?>\n"
  	"<!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN'\n"
  	"'DTD/xhtml1-transitional.dtd'>\n"
  	"<html xmlns='http://www.w3.org/1999/xhtml'>\n"
  	"<head>\n"
  	"  <meta http-equiv='Content-Type' content='text/html; charset=UTF-8'/>\n"
  	"</head>\n"
  	"<body>\n"
  	"<h1>Release tests report table</h1>\n"
  	"<TABLE border=\"1\" cellpadding=\"2\" cellspacing=\"0\" width=\"100%\">\n"
  	"  <TR align=\"center\"><TH>Test</TH><TH>Result</TH></TR>\n"+
  	rez+
  	"</TABLE>\n"
  	"</body>"
  	"</html>");


ID: archPackFStests
NAME: TEST: FS archiver pack
DESCR:
  Archiving to File System tests pack, for check the optimization algorithm.  The stages supported:
    - Stage 0: Main values fill: "1,1,10,10,100,100,1000,1000,10000,10000,EVAL"
    - Stage 1: Change to different value 20: "1,1,20,10,100,100,1000,1000,10000,10000,EVAL"
    - Stage 2: Set value for merge, equal, to up 10: "1,1,20,10,10,100,1000,1000,10000,10000,EVAL"
    - Stage 3: Set value for merge, equal, to down 1000: "1,1,20,10,10,1000,1000,1000,10000,10000,EVAL"
    - Stage 4: Set different value to end 20000: "1,1,20,10,10,1000,1000,1000,10000,10000,20000,EVAL"
    - Stage 5: Change end value for merge to up 10000: "1,1,20,10,10,1000,1000,1000,10000,10000,10000,EVAL"
    - Stage 6: Set value to end for merge to up 10000: "1,1,20,10,10,1000,1000,1000,10000,10000,10000,10000,EVAL"
    - Stage 7: Set to end value EVAL: "1,1,20,10,10,1000,1000,1000,10000,10000,10000,EVAL"
    - Stage 8: Set equal value to insert 10000: "1,1,20,10,10,1000,1000,1000,10000,10000,10000,EVAL"
  Author: Roman Savochenko <rom_as@oscada.org>
  Version: 1.0.0

FORMULA:
  using Special.FLibSYS;
  arh = vArh("Archive.va_"+addr);

  //Stage 0: Main values fill: "1,1,10,10,100,100,1000,1000,10000,10000,EVAL"
  if(step < 0 || step == 0) {
  	buf = vArhBuf(1, 10, per*1000000, true, true);
  	for(iV = 0; iV < 10; iV++) buf.set(pow(10,floor(iV/2)), tm+iV*per, 0);
  	arh.copy(buf, buf.begin(), 0, buf.end(), 0, archiver);
  }

  //Stage 1: Change to different value 20: "1,1,20,10,100,100,1000,1000,10000,10000,EVAL"
  if(step < 0 || step == 1) {
  	buf = vArhBuf(1, 10, per*1000000, true, true);
  	buf.set(20, tm+2*per, 0); arh.copy(buf, buf.begin(), 0, buf.end(), 0, archiver);
  }

  //Stage 2: Set value for merge, equal, to up 10: "1,1,20,10,10,100,1000,1000,10000,10000,EVAL"
  if(step < 0 || step == 2) {
  	buf = vArhBuf(1, 10, per*1000000, true, true);
  	buf.set(10, tm+4*per, 0); arh.copy(buf, buf.begin(), 0, buf.end(), 0, archiver);
  }

  //Stage 3: Set value for merge, equal, to down 1000: "1,1,20,10,10,1000,1000,1000,10000,10000,EVAL"
  if(step < 0 || step == 3) {
  	buf = vArhBuf(1, 10, per*1000000, true, true);
  	buf.set(1000, tm+5*per, 0); arh.copy(buf, buf.begin(), 0, buf.end(), 0, archiver);
  }

  //Stage 4: Set different value to end 20000: "1,1,20,10,10,1000,1000,1000,10000,10000,20000,EVAL"
  if(step < 0 || step == 4) {
  	buf = vArhBuf(1, 10, per*1000000, true, true);
  	buf.set(20000, tm+10*per, 0); arh.copy(buf, buf.begin(), 0, buf.end(), 0, archiver);
  }

  //Stage 5: Change end value for merge to up 10000: "1,1,20,10,10,1000,1000,1000,10000,10000,10000,EVAL"
  if(step < 0 || step == 5) {
  	buf = vArhBuf(1, 10, per*1000000, true, true);
  	buf.set(10000, tm+10*per, 0); arh.copy(buf, buf.begin(), 0, buf.end(), 0, archiver);
  }

  //Stage 6: Set value to end for merge to up 10000: "1,1,20,10,10,1000,1000,1000,10000,10000,10000,10000,EVAL"
  if(step < 0 || step == 6) {
  	buf = vArhBuf(1, 10, per*1000000, true, true);
  	buf.set(10000, tm+11*per, 0); arh.copy(buf, buf.begin(), 0, buf.end(), 0, archiver);
  }

  //Stage 7: Set to end value EVAL: "1,1,20,10,10,1000,1000,1000,10000,10000,10000,EVAL"
  if(step < 0 || step == 7) {
  	buf = vArhBuf(1, 10, per*1000000, true, true);
  	buf.set(EVAL_INT, tm+11*per, 0); arh.copy(buf, buf.begin(), 0, buf.end(), 0, archiver);
  }

  //Stage 8: Set equal value to insert 10000: "1,1,20,10,10,1000,1000,1000,10000,10000,10000,EVAL"
  if(step < 0 || step == 8) {
  	buf = vArhBuf(1, 10, per*1000000, true, true);
  	buf.set(10000, tm+9*per, 0); arh.copy(buf, buf.begin(), 0, buf.end(), 0, archiver);
  }


# flb_regEl

ID: pidUnif
NAME: PID (unified)
uk#NAME: ПІД (уніфікований)
ru#NAME: ПИД (унифицированный)
DESCR:
  Composite-unified analog and pulse PID. At the heart of the regulator is core a standard analog PID controller from the library "FLibComplex1" (http://wiki.oscada.org/HomePageEn/Doc/FLibComplex1#h902-15) and the implementation of the PWM for the pulse part.

uk#DESCR:
  Суміщений-уніфікований аналоговий та імпульсний ПІД-регулятор. У основі регулятора лежить мова стандартного аналогового ПІД-регулятора з бібліотеки "FLibComplex1" та реалізація ШІМ для імпульсної частини.

ru#DESCR:
  Совмещённый-унифицированный аналоговый и импульсный ПИД-регулятор. В основе регулятора лежит ядро стандартного аналогового ПИД-регулятора из библиотеки "FLibComplex1" (http://wiki.oscada.org/Doc/FLibComplex1#h91-15) и реализация ШИМ для импульсной части.

FORMULA:
  //Call standard analog PID
  outA = Special.FLibComplex1.pid(var,sp,max,min,manIn,auto,casc,Kp,Ti,Kd,Td,Tzd,Hup,Hdwn,Zi,followSp,K1,in1,K2,in2,K3,in3,K4,in4,f_frq,int,dif,lag);
  if(analog) return outA;

  if(f_start || f_stop) { impQup = impQdwn = false; return 0; }

  //Call impuls generator
  outA = 2*(outA-50);
  if(perLag <= 0 && ((outA*KImpRfact) >= (100*TImpMin/TImpPer) || (-outA/KImpRfact) >= (100*TImpMin/TImpPer) || (!auto && abs(outA) > 0.1)))
  {
  	impLag = max(abs(outA)*TImpPer/100, TImpMin);
  	impLag = (outA>0) ? impLag*KImpRfact : impLag/KImpRfact;
  	perLag = TImpPer;
  	if(outA > 0) impQup = true; else impQdwn = true;  
  }
  else if(perLag > 0) {
  	perLag -= 1e3/f_frq;
  	if((TImpPer-perLag) >= impLag) {
  		impQup = impQdwn = false;
  		if(!auto) perLag = 0;
  	}
  }

  if(!auto) manIn = 50;

  if(impQupTm > 1 || (impQupTm && !impQup)) impQupTm--;
  if(impQup && !impQupTm) impQupTm = 2*f_frq;
  if(impQdwnTm > 1 || (impQdwnTm && !impQdwn)) impQdwnTm--;
  if(impQdwn && !impQdwnTm) impQdwnTm = 2*f_frq;

  if(impAnImit) {
  	if(impQup)	out += 100/(impAnOut*f_frq);
  	if(impQdwn)	out -= 100/(impAnOut*f_frq);
  	return max(0,min(100,out));
  }
  return impAnOut;


ID: pidUnifD
NAME: PID dynamic
uk#NAME: ПІД динамічний
ru#NAME: ПИД динамический
DESCR:
  Completely identical to unified PID regulator is implemented dynamically on JavaLikeCalc. The dynamic implementation allows you to easily adapt the regulator to the desired requirements, simply by editing it.

uk#DESCR:
  Повністю ідентичний уніфікованому ПІД регулятор, реалізований динамічно на JavaLikeCalc. Динамічна реалізація дозволяє легко адаптувати регулятор під потрібні вимоги, просто відредагувати його.

ru#DESCR:
  Полностью идентичный унифицированному ПИД регулятор, реализованный динамически на JavaLikeCalc. Динамическая реализация позволяет легко адаптировать регулятор под нужные требования, просто отредактировав его.

FORMULA:
  if(f_start) {
  	auto_ = auto;
  	outA = out;
  	impQupTm_ = impQdwnTm_ = 0;
  	impQup_ = impQdwn_ = 0;
  }

  //Call standard analog PID
  Kzd = min(1e3/(f_frq*Tzd),1);
  Kint = min(1e3/(f_frq*Ti),1);
  Kdif = min(1e3/(f_frq*Td),1);

  //Scale error
  if(var.isEVal() || max <= min) return out;
  sp = max(min,min(max,sp));

  //Prepare values
  spv = 100*(sp-min)/(max-min);
  val = 100*(var-min)/(max-min);
  val += K1*in1 + K2*in2;
  val = min(100,max(-100,val));

  //Error
  err = spv - val;
  err = (abs(err)<Zi) ? 0 : ((err>0) ? err-Zi : err+Zi );
  err *= Kp;
  err = min(100,max(-100,err));

  integ += Kint*err;						//Integral
  difer -= Kdif*(difer-val);			//Differential wait
  dlag  += Kzd*((difer-val)-dlag);	//Differential lag

  //Automatic mode enabled
  if(auto) {
  	outA_ = err + integ + Kd*dlag + K3*in3 + K4*in4;
  	if(QO) outA_ = min(outA, outA_);
  	if(QZ) outA_ = max(outA, outA_);
  	outA = outA_;
  }
  else {
  	casc = false;
  	if(followSp) sp = var;
  	outA = manIn;
  }

  //Check output limits
  outA = manIn = min(Hup,max(Hdwn,outA));

  //Fix integral for manual and limits
  integ = outA - err - Kd*dlag - K3*in3 - K4*in4;

  if(analog) return outA;

  if(f_start || f_stop) { impQup = impQdwn = false; return 0; }

  //Call impuls generator
  outA_ = (impAnOut < 0) ? 2*(outA-50) : (outA-impAnOut);
  if(perLag <= 0 && ((outA_*KImpRfact) >= (100*TImpMin/TImpPer) || (-outA_/KImpRfact) >= (100*TImpMin/TImpPer)))
  {
  	impLag = max(abs(outA_)*TImpPer/100,TImpMin);
  	impLag = (outA_>0) ? impLag*KImpRfact : impLag/KImpRfact;
  	perLag = TImpPer;
  	if(outA_ > 0) impQup = !QO; else impQdwn = !QZ;
  }
  else if(perLag > 0) {
  	perLag -= 1e3/f_frq;
  	if((TImpPer-perLag) >= impLag) {
  		impQup = impQdwn = false;
  		if(!auto) perLag = 0;
  	}
  }

  if(!auto && auto != auto_)	manIn = (impAnOut < 0) ? 50 : impAnOut;
  auto_ = auto;

  if(impQup && !impQup_) impQupTm_ = 2*f_frq;
  impQupTm_ = max(0,impQupTm_-1);
  impQupTm = (impQup || impQupTm_ > 0.1);
  impQup_ = impQup;
  if(impQdwn && !impQdwn_) impQdwnTm_ = 2*f_frq;
  impQdwnTm_ = max(0,impQdwnTm_-1);
  impQdwnTm = (impQdwn || impQdwnTm_ > 0.1);
  impQdwn_ = impQdwn;

  if(impAnImit > 0) {
  	if(impQup)	out += 100/(impAnImit*f_frq);
  	if(impQdwn)	out -= 100/(impAnImit*f_frq);
  	return max(0, min(100,out));
  }
  return max(0, min(100,impAnOut));


ID: pidImp
NAME: PID pulse
uk#NAME: ПІД імпульсний
ru#NAME: ПИД импульсный
DESCR:
  Specialized pulse PID regulator is implemented on a special algorithm with compensation of double integration.

uk#DESCR:
  Спеціалізований імпульсний ПІД регулятор реалізований за особливим алгоритмом з компенсацією подвійного інтегрування.

ru#DESCR:
  Специализированный импульсный ПИД регулятор реализованный по особому алгоритму с компенсацией двойного интегрирования.

FORMULA:
  //Call standard analog PID
  Kzd = min(1e3/(f_frq*Tzd), 1);
  Kint = min(1e3/(f_frq*Ti), 1);
  Kdif = min(1e3/(f_frq*Td), 1);

  //Scale error
  if(max <= min) return 0;

  //Prepare values
  spv = 100*(sp-min)/(max-min);
  val = 100*(var-min)/(max-min);
  val += K1*in1 + K2*in2;
  val = min(100,max(-100,val));

  //Error
  err = spv - val;
  err = (abs(err)<Zi) ? 0 : ((err>0) ? err-Zi : err+Zi );
  err *= Kp;
  err = min(100,max(-100,err));
  errP = err-err1;
  errD = err1-err2;
  err2 = err1; err1 = err;

  integ += Kint*err;							//Integral
  difer -= Kdif*(difer-errD);				//Differecial wait
  dlag  += Kzd*((errP-difer)-dlag);	//Differecial lag

  //Automatic mode enabled
  if(auto) { outPID = errP + Ki*err + integ + Kd*dlag; outA = 50 + outPID + K3*in3 + K4*in4; }
  else {
  	outPID = 0;
  	casc = false;
  	if(followSp) sp = var;
  	outA = manIn;
  }

  //Check output limits
  outA = manIn = min(Hup, max(Hdwn,outA));

  //Fix integral for manual and limits
  //integ = outA - errP - Kd*dlag - K3*in3 - K4*in4;

  if(f_start || f_stop) { impQup = impQdwn = false; return 0; }

  //Call impuls generator
  outA = 2*(outA-50);
  if(perLag <= 0 && ((outA*KImpRfact) >= (100*TImpMin/TImpPer) || (-outA/KImpRfact) >= (100*TImpMin/TImpPer) || (!auto && abs(outA) > 0.1)))
  {
  	impLag = max(abs(outA)*TImpPer/100,TImpMin);
  	impLag = (outA > 0) ? impLag*KImpRfact : impLag/KImpRfact;
  	perLag = TImpPer;
  	if(outA > 0) impQup = true; else impQdwn = true;  
  }
  else if(perLag > 0) {
  	perLag -= 1e3/f_frq;
  	if((TImpPer-perLag) >= impLag) {
  		impQup = impQdwn = false;
  		if(!auto) perLag = 0;
    }
  }

  if(!auto) manIn = 50;

  if(impQupTm > 1 || (impQupTm && !impQup)) impQupTm--;
  if(impQup && !impQupTm) impQupTm = 2*f_frq;
  if(impQdwnTm > 1 || (impQdwnTm && !impQdwn)) impQdwnTm--;
  if(impQdwn && !impQdwnTm) impQdwnTm = 2*f_frq;

  if(impQup || impQdwn) integ = 0;

  if(impAnImit) {
  	if(impQup) out += 100/(impAnOut*f_frq);
  	if(impQdwn) out -= 100/(impAnOut*f_frq);
  	return max(0, min(100,out));
  }
  return impAnOut;


# UserProtocol_uPrt

ID: SMS
DESCR:
  Provides operations with SMS by GSM-modem connected as serial device. For now supported only sending SMS messages to a number of remote cell phone or GSM modem.
  Author: Roman Savochenko <rom_as@oscada.org>
  Version: 2.1.1

OutPROG:
  JavaLikeCalc.JavaScript
  //Request form:
  //<{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 for 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.

  //Transport's timings check
  if(tr.timings() != "5000:100")	tr.timings("5000:100");

  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("Disable ECHO error: %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("Check for PIN-code error: %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("Set PIN error: %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("Set SMS Text mode error: %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("Sent SMS error: %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("Sent SMS PDU error: %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("Set SMS PDU mode error: %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("Sent SMS error: %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("Sent SMS PDU error: %1").replace("%1",rez)); return; }
  		//SYS.messDebug("TEST SMS","PDU REZ :"+rez);
  	}
  	io.setAttr("err", "0");
  }


ID: SCU750
NAME: EDWARDS TURBOMOLECULAR PUMPS
DESCR:
  Protocol level of typical EDWARDS TURBOMOLECULAR PUMPS (http://edwardsvacuum.com) data request by SCU750 Cotrol Unit protocol.
  Author: Roman Savochenko <rom_as@oscada.org>
  Sponsored: Vasiliy Grigoriev from "Vacuum technologies laboratory (http://e-beam.ru)".

OutPROG:
  JavaLikeCalc.JavaScript
  //Request form:
  //<mess addr="1" err="1:Error">{req}</mess> - message tag
  //  req - request/respond data;
  //  addr - remote station address (<0 - single; >=0 - multi port);
  //  err - sets for the request result.
  if(io.text().length > 255*255) { io.setAttr("err","1:"+tr("Message's length more 255*255")); return; }
  addr = io.attr("addr").toInt();
  k = ceil(io.text().length/255);	//transmission blocks
  for(i_k = 1; i_k <= k; i_k++) {
  	request = "\x02"+k.toString(16,3) + io.text().slice((i_k-1)*255,(i_k-1)*255+min(255,io.text().length-(i_k-1)*255)) + ((k>1&&i_k<k)?"\x17":"\x03");
  	// Calc LRC
  	LRC = 0xFF;
  	for(i = 0; i < request.length; i++) LRC = LRC^request.charCodeAt(i);
  	request += SYS.strFromCharCode(LRC);

  	// Multy port
  	if(addr>=0) request = "@"+addr.toString(16,2)+request;
  	//SYS.messDebug("PRT","Request: "+Special.FLibSYS.strDec4Bin(request));

  	//Send the request
  	resp = tr.messIO(request);
  	while(resp.length) {
  		tresp = tr.messIO("");
  		if(!tresp.length) break;
    		resp += tresp;
  	}
  	if(!resp.length) { io.setAttr("err","2:"+tr("No respond")); return; }
  	//SYS.messDebug("PRT","Ack: "+Special.FLibSYS.strDec4Bin(resp));
  	if(resp.charCodeAt(0) != 6) { io.setAttr("err","3:"+tr("No acknowledgment")); return; }
  	// Pass included acknowledgement
  	resp = resp.slice((addr>=0)?3:1);

  	// Read data blocks
  	io.setText("");
  	for(i_k = 1; true; i_k++) {
  		//Send application acknowledgement and wait data
  		if(!resp.length) {
  			request = "\x06";
  			if(addr >= 0) request += addr.toString(16,2);
  			resp = tr.messIO(request);
  			while(resp.length) {
  				tresp = tr.messIO("");
  				if(!tresp.length) break;
    				resp += tresp;
  			}
  			if(!resp.length) { io.setAttr("err","4:"+tr("No data block get")); return; }
  		}
  		if(resp.length < ((addr>=0)?10:7) || resp.charCodeAt(0) != 0x40) { io.setAttr("err","5:"+tr("Data block short or error")); return; }

  		//SYS.messDebug("PRT","BLK "+i_k+": "+Special.FLibSYS.strDec4Bin(resp));

  		if(addr >= 0) resp = resp.slice(3);
  		LRC = 0xFF;
  		for(i = 0; i < (resp.length-1); i++) LRC = LRC^resp.charCodeAt(i);
  		if(LRC != resp.charCodeAt(resp.length-1)) { io.setAttr("err","6:"+tr("LRC error.")); return; }
  		if(i_k != resp.slice(1,4).toInt(16)) { io.setAttr("err","7:"+tr("Block sequence.")); return; }
  		io.setText(io.text()+resp.slice(4,resp.length-2));
  		if(resp.charCodeAt(resp.length-2) == 0x03) break;
  		if(resp.charCodeAt(resp.length-2) == 0x17) { resp = ""; continue; }
  		io.setAttr("err","8:"+tr("Unknown block end."));
  		return;
  	}
  }


ID: TMH
NAME: Power supply for turbomolecular pumps
DESCR:
  Protocol level of power supply for turbomolecular pumps of firm SHIMADZU (http://www.shimadzu.com), model EI-R04M.
  Author: Roman Savochenko <rom_as@oscada.org>
  Sponsored: Vasiliy Grigoriev from "Vacuum technologies laboratory (http://e-beam.ru)".

OutPROG:
  JavaLikeCalc.JavaScript
  //Request form:
  //<mess addr="1" err="1:Error">{req}</mess> - message tag
  //  req - request/respond data;
  //  addr - remote station address (1...32);
  //  err - sets for the request result.

  io.setAttr("err","");
  addr = io.attr("addr").toInt();
  if(addr < 1 || addr > 32) { io.setAttr("err","1:"+tr("Device address out of range 1...32")); return; }
  request = "MJ"+addr.toString(10,2)+io.text();
  //Calc CRC
  CRC = 0;
  for(i = 0; i < request.length; i++) CRC += request.charCodeAt(i);
  request += (CRC&0xFF).toString(16,2)+"\r";
  //SYS.messDebug("PRT","Request: "+Special.FLibSYS.strDec4Bin(request));

  //Send request
  resp = tr.messIO(request);
  while(resp.length && resp[resp.length-1] != "\r") {
  	tresp = tr.messIO("");
  	if(!tresp.length) break;
    	resp += tresp;
  }
  if(resp.length < 6 || resp[resp.length-1] != "\r" || resp.slice(0,2) != "MJ" || resp.slice(2,4).toInt() != addr)
  { io.setAttr("err","2:"+tr("No or error respond")); return; }
  //SYS.messDebug("PRT","Respond: "+Special.FLibSYS.strDec4Bin(resp));
  CRC = 0;
  for(i = 0; i < (resp.length-3); i++) CRC += resp.charCodeAt(i);
  if((CRC&0xFF) != resp.slice(resp.length-3,resp.length-1).toInt(16)) { io.setAttr("err","6:"+tr("CRC error.")); return; }
  io.setText(resp.slice(4,resp.length-3));


ID: VKT7
NAME: VKT-7
DESCR:
  Protocol level of firm "Teplocom" (http://www.teplocom.spb.ru) computer "VKT-7" for complex heat measurement and the count. The device complex enough by provide more parameters, more history to its and access by nonlinear Serial-based protocol at low speed.
  Author: Roman Savochenko <rom_as@oscada.org>
  Sponsored: Vladislav Chubuk

OutPROG:
  JavaLikeCalc.JavaScript
  //Request form:
  //<mess addr="1" err="1:Error">{req}</mess> - message tag
  //  req - request/respond data;
  //  addr - remote station address (0...254);
  //  err - sets for the request result.
  io.setAttr("err", "");
  addr = io.attr("addr").toInt();
  if(addr < 0 || addr > 254) { io.setAttr("err", "1:"+tr("Device address out of range 0...254")); return; }
  request = SYS.strFromCharCode(addr) + io.text();
  //Calc KS
  KS = 0xFFFF;
  for(i = 0; i < request.length; i++) {
  	KS = KS ^ request.charCodeAt(i);
  	for(j = 0; j < 8; j++)
  		KS = (KS&0x01) ? (KS >> 1)^0xA001 : (KS >> 1);
  }
  request = SYS.strFromCharCode(0xFF,0xFF) + request + SYS.strFromCharCode(KS,KS>>8);
  SYS.messDebug("/VKT7/PRT","Request: "+Special.FLibSYS.strDec4Bin(request));

  //Send request
  resp = tr.messIO(request);
  while(resp.length) {
  	tresp = tr.messIO("");
  	if(!tresp.length) break;
    	resp += tresp;
  }
  if(resp.length < 4 || resp.charCodeAt(0) != addr)	{ io.setAttr("err", "2:"+tr("No or error respond")); return; }
  SYS.messDebug("/VKT7/PRT","Respond: "+Special.FLibSYS.strDec4Bin(resp));

  //Calc KS
  KS = 0xFFFF;
  for(i = 0; i < (resp.length-2); i++) {
  	KS = KS ^ resp.charCodeAt(i);
  	for(j = 0; j < 8; j++)
  		KS = (KS&0x01) ? (KS >> 1)^0xA001 : (KS >> 1);
  }
  if(KS != ((resp.charCodeAt(resp.length-1)<<8)|resp.charCodeAt(resp.length-2)))
  { io.setAttr("err","6:"+tr("KS error")+" "+KS.toString(16,4)+"=="+((resp.charCodeAt(resp.length-1)<<8)|resp.charCodeAt(resp.length-2)).toString(16,4)); return; }
  if(resp.charCodeAt(1)&0x80)
  { io.setAttr("err","7:"+resp.charCodeAt(2)+":"+tr("Request error.")); return; }
  io.setText(resp.slice(1,-2));


ID: DCON
NAME: DCON
DESCR:
  Mostly aimed for example implement user protocols into OpenSCADA and contains only main functions into the protocol part.
  Author: Roman Savochenko <rom_as@oscada.org>
  Version: 1.0.1

InPROG:
  JavaLikeCalc.JavaScript
  //Processing: test implements only processing for requests '#' and '@' with fixed reply data.

  var enCRC = true;
  //SYS.messDebug("/DCON/in","REQ: "+request);
  //Test request for full
  if(request.length < 4 || request[request.length-1] != "\r") {
    if(request.length > 10) request = "";
    return true;
  }
  //Check for integrity of the request (CRC) and address
  if(enCRC) {
  	CRC = 0;
  	for(i = 0; i < (request.length-3); i++) CRC += request.charCodeAt(i);
  	if(CRC != request.slice(request.length-3,request.length-1).toInt(16) || request.slice(1,3).toInt(16) != 10) return false;
  }
  //Analysis of the request and response prepare
  if(request[0] == "#") answer = ">+05.123+04.153+07.234-02.356+10.000-05.133+02.345+08.234";
  else if(request[0] == "@") answer = ">AB3C";
  else answer = "?";
  //Finish response
  if(enCRC) {
  	CRC = 0;
  	for(i=0; i < answer.length; i++) CRC += answer.charCodeAt(i);
  	answer += (CRC&0xFF).toString(16)+"\r";
  }
  //SYS.messDebug("/DCON/in","ANSV: "+answer[0]);
  return 0;

OutPROG:
  JavaLikeCalc.JavaScript
  //Request form:
  //<ReqSymb addr="1" err="1:Error">{req}</ReqSymb> - message tag
  //  ReqSymb - request type symbol into the tag name, like: '#', '@', etc
  //  req - request/respond data;
  //  addr - remote host address [1...240];
  //  err - sets for the request result.

  //Result request prepare
  request = io.name().slice(0,1) + io.attr("addr").toInt().toString(16,2) + io.text();
  if(io.attr("CRC").toInt()) {
  	CRC = 0;
  	for(i = 0; i < request.length; i++) CRC += request.charCodeAt(i);
  	request += (CRC&0xFF).toString(16) + "\r";
  }
  else request += "\r";
  //Send request
  resp = tr.messIO(request);
  while(resp[resp.length-1] != "\r") {
    tresp = tr.messIO("");
    if(!tresp.length) break;
    resp += tresp;
  }
  if(io.attr("CRC").toInt()) {
  	//Analysis response
  	if(resp.length < 4 || resp[resp.length-1] != "\r") { io.setAttr("err","10:"+tr("Error or no response.")); return; }
  	//Check response to the integrity (CRC)
  	CRC = 0;
  	for(i = 0; i < (resp.length-3); i++) CRC += resp.charCodeAt(i);
  	if(CRC != resp.slice(resp.length-3,resp.length-1).toInt(16)) { io.setAttr("err","11:"+tr("CRC error.")); return; }
  }
  //Analysis response
  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; }
  //The result return
  io.setAttr("err","");
  io.setText(resp.slice(1,resp.length-3));


ID: TM510x
NAME: Elemer TM510x
DESCR:
  Protocol level of multichannels thermometer Elemer TM5102 and TM5103 of firm Elemer (http://www.elemer.ru).
  Author: Roman Savochenko <rom_as@oscada.org>

OutPROG:
  JavaLikeCalc.JavaScript
  //Request form:
  //<mess addr="1" err="1:Error">{req}</mess> - message tag
  //  req - request/respond data;
  //  addr - remote station address (1...254);
  //  err - sets for the request result.
  io.setAttr("err", "");
  addr = io.attr("addr").toInt();
  if(addr < 1 || addr > 254) { io.setAttr("err","1:"+tr("Device address out of range 1...254")); return; }
  request = ":"+addr.toString(10)+";"+io.text()+";";
  //Calc KS
  KS = 0xFFFF;
  for(i = 1; i < request.length; i++) {
  	KS = KS ^ request.charCodeAt(i);
  	for(j = 0; j < 8; j++)
  		KS = (KS&0x01) ? (KS >> 1)^0xA001 : (KS >> 1);
  }
  request += KS.toString(10)+"\r";
  //SYS.messDebug("PRT","Request: "+request);

  //Send request
  resp = tr.messIO(request);
  while(resp.length && resp[resp.length-1] != "\r") {
  	tresp = tr.messIO("");
  	if(!tresp.length) break;
    	resp += tresp;
  }
  if(resp.length && resp.charCodeAt(0) == 0xFF) resp = resp.slice(1);
  if(resp.length < 7 || resp[resp.length-1] != "\r" ||
  	resp[0] != "!" || resp.slice(1).toInt() != addr || (KSpos=resp.lastIndexOf(";")) < 0)
  { io.setAttr("err","2:"+tr("No or error respond")); return; }
  //SYS.messDebug("PRT","Respond: "+resp);

  //Calc KS
  KS = 0xFFFF;
  for(i = 1; i < min(KSpos+1,resp.length); i++) {
  	KS = KS ^ resp.charCodeAt(i);
  	for(j = 0; j < 8; j++)
  		KS = (KS&0x01) ? (KS >> 1)^0xA001 : (KS >> 1);
  }
  if(KS != resp.slice(KSpos+1).toInt(10)) { io.setAttr("err","6:"+tr("KS error.")); return; }
  io.setText(resp.slice(resp.indexOf(";")+1,KSpos));


ID: SMDP
NAME: Sycon Multi Drop Protocol
DESCR:
  Protocol level of 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 <rom_as@oscada.org>
  Sponsored: Vasiliy Grigoriev from "Vacuum technologies laboratory (http://e-beam.ru)".

OutPROG:
  JavaLikeCalc.JavaScript
  //Request form:
  //<mess addr="16" try="1" err="1:Error">{req}</mess> - message tag
  //req - request/respond data;
  //addr - remote device address [16...254];
  //try - tries for the request;
  //err - sets for the request result.

  if(!io.text().length) { io.setAttr("err","1:"+tr("Message empty")); return; }
  addr = io.attr("addr").toInt();
  try = min(5,max(1,io.attr("try").toInt()));
  request = "\x02"+SYS.strFromCharCode(addr) + io.text();
  //Calc CHKSUM
  CRC = 0;
  for(i = 1; i < request.length; i++) CRC += request.charCodeAt(i);
  request += SYS.strFromCharCode((CRC>>4&0xF)+0x30,(CRC&0xF)+0x30,0x0D);

  SYS.messDebug("/UserProt/SMDP",tr("Request:")+" "+Special.FLibSYS.strDec4Bin(request));

  for( ; try > 0; try--) {
  	//Send the request
  	resp = tr.messIO(request);
  	while(resp.length && resp.charCodeAt(resp.length-1) != 0x0D)
  		if((tresp=tr.messIO("")).length) resp += tresp;
  		else break;

  	if(!resp.length)	{ io.setAttr("err","2:"+tr("No respond")); continue; }
  	if(resp.length < 6 || resp.charCodeAt(resp.length-1) != 0x0D)	{ io.setAttr("err","3:"+tr("Not full respond")); continue; }
  	if(resp.charCodeAt(0) != 0x02 || resp.charCodeAt(1) != addr)	{ io.setAttr("err","4:"+tr("Wrong respond")); continue; }

  	SYS.messDebug("/UserProt/SMDP",tr("Respond:")+" "+Special.FLibSYS.strDec4Bin(resp));

  	CRC = 0;
  	for(i = 1; i < (resp.length-3); i++) CRC += resp.charCodeAt(i);
  	if((CRC&0xFF) != (((resp.charCodeAt(resp.length-3)-0x30)<<4)|(resp.charCodeAt(resp.length-2)-0x30)))
  	{ io.setAttr("err","6:"+tr("CRC error.")); continue; }
  	break;
  }
  if(try <= 0)	return;

  errCd = resp.charCodeAt(2)&0x7;
  if(errCd == 1) io.setAttr("err","").setText(resp.slice(2,-2));
  else if(errCd == 2) io.setAttr("err",""+(10+errCd)+":Err_inv_cmd: "+tr("Illegal command (CMD code not valid)."));
  else if(errCd == 3) io.setAttr("err",""+(10+errCd)+":Err_syntax: "+tr("Syntax error. (Too many bytes in data field, not enough bytes, etc)."));
  else if(errCd == 4) io.setAttr("err",""+(10+errCd)+":Err_range: "+tr("Data range error."));
  else if(errCd == 5) io.setAttr("err",""+(10+errCd)+":Err_inhibited: "+tr("Inhibited."));
  else if(errCd == 6) io.setAttr("err",""+(10+errCd)+":Err_obso: "+tr("Obsolete command. No action taken, but not really an error."));
  else io.setAttr("err",""+(10+errCd)+":"+tr("Unknown error."));


ID: OWEN
NAME: OWEN
DESCR:
  Protocol level of mostly models of OWEN devices by specific protocol.
  Author: Constantine (IrmIngeneer)
  Refactoring: Roman Savochenko <rom_as@oscada.org>

OutPROG:
  JavaLikeCalc.JavaScript
  //Request form:
  //<mess addr="1" err="1:Error">{req}</mess> - message tag
  //  req - request/respond data;
  //  addr - remote station address (0...2047);
  //  err - sets for the request result.
  io.setAttr("err", "");
  addr = io.attr("addr").toInt();
  if(addr < 0 || addr > 2047) { io.setAttr("err", "1:"+tr("Device address out of range 0...2047")); return; }
  request = SYS.strFromCharCode((addr<256)?addr:addr>>3, ((addr<256)?0:addr<<5)|0x10) + io.text();

  // CRC append
  for(CRC = 0, i = 0; i < request.length; i++) {
  	b = request.charCodeAt(i);
  	for(j = 0; j < 8; j++, b = b << 1)
  		CRC = ((b^(CRC>>8)&0x80)?(CRC<<1)^0x8F57:CRC<<1) & 0xFFFF;
  }
  request += SYS.strFromCharCode(CRC>>8, CRC&255);

  // Convert to ASCII
  for(reqASCII = "", i = 0; i < request.length; i++)
  	reqASCII += SYS.strFromCharCode((request.charCodeAt(i)>>4)+71, (request.charCodeAt(i)&0x0F)+71);

  // Result request
  request = "#" + reqASCII + "\r";

  //Send the request and get respond
  for(resp = tr.messIO(request); resp[resp.length-1] != "\r" && (respTail=tr.messIO("")).length; ) resp += respTail;

  //Respond process
  if(resp.length < 14 || resp[resp.length-1] != "\r" || resp[0] != "#" || (resp.length%2) != 0) {
  	io.setAttr("err", "10:"+tr("Wrong or no a respond."));
  	return; 
  }

  // Remove markers
  resp = resp.slice(1, resp.length-1);

  // Convert 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;

  // Check for CRC
  for(CRC = 0, i = 0; i < resp.length-2; i++) {
  	b = resp.charCodeAt(i);
  	for(j = 0; j < 8; j++, b = b << 1)
  		CRC = ((b^(CRC>>8)&0x80)?(CRC<<1)^0x8F57:CRC<<1) & 0xFFFF;
  }
  if(CRC != ((resp.charCodeAt(resp.length-2)<<8)+resp.charCodeAt(resp.length-1))) {
  	io.setAttr("err", "11:"+tr("CRC error."));
  	return;
  }

  //Return result
  io.setText(resp.slice(0,resp.length-2));


ID: IT3
NAME: Temperature measurement IT-3
DESCR:
  Protocol level of temperature measurement IT-3 from OmskEtalon (http://www.omsketalon.ru).
  Author: Roman Savochenko <rom_as@oscada.org>
  Sponsored: Vasiliy Grigoriev from "Vacuum technologies laboratory (http://e-beam.ru)".
  Version: 1.2.0

InPROG:
  JavaLikeCalc.JavaScript
  // Input part of the protocol IT-3
  // for work into the background/listen mode to an other interaction session.
  var prm;
  if(prm.isEVal())	prm = SYS.nodeAt("/DAQ/LogicLev/cryo/prm_IT3");
  if(prm.isEVal())	return false;	//Drop all request but the target parameter's object wrong
  if(!request.length) {					//Empty request means it is not a data for the pointed time, 1 second
  	prm.err.set("1:"+tr("No data"), 0, 0, true);
  	prm.T.set(EVAL, 0, 0, true);
  	prm.relSt.set(EVAL, 0, 0, true);
  	prm.L.set(EVAL, 0, 0, true);
  	prm.H.set(EVAL, 0, 0, true);
  	return true;
  }
  //SYS.messDebug("/IT3/IN","TEST 00: req="+SYS.strDecode(request,"Bin"," "));

  while(request.length >= 6) {	//the full header
  	if(request.charCodeAt(0) != 0x16)	{ request = ""; break; }		//The package is broken, drop full

  	if((6+(blkLen=request.charCodeAt(1))) > request.length)	break;	//The package is not full, wait

  	//The package's header control sum check and pass broken packages
  	for(KS = 0, i = 1; i < 4; i++) KS += request.charCodeAt(i);
  	KS = (~(KS+1))&0xFFFF;
  	if(((request.charCodeAt(5)<<8)+request.charCodeAt(4)) != KS) { request = request.slice(6+blkLen); continue; }

  	//The package's body control sum check and pass broken packages
  	for(KS = 0, i = 6; i < (6+blkLen-2); i++) KS += request.charCodeAt(i);
  	KS = (~(KS+1))&0xFFFF;
  	if(((request.charCodeAt(6+blkLen-1)<<8)+request.charCodeAt(6+blkLen-2)) != KS)	{ request = request.slice(6+blkLen); continue; }

  	if(request.charCodeAt(2))	{ request = request.slice(6+blkLen); continue; }	//The package is a request, pass

  	//Info respond package
  	if(request.charCodeAt(6) == 0x80)
  		prm.err.set((errCode=request.charCodeAt(6+1))?("5:"+errCode+":"+tr("Request error")):"0", 0, 0, true);
  	//Data respond package
  	if(request.charCodeAt(6) == 0x85) {
  		errCode = 0;//prm.err.get().toInt();
  		cntrB = request.charCodeAt(6+3);
  		T = errCode ? EVAL : ((request.charCodeAt(6+2)<<8)+request.charCodeAt(6+1));
  		if(!T.isEVal())	T = T/((cntrB&0x8)?100:10);
  		prm.T.set(T, 0, 0, true);
  		prm.relSt.set(errCode?EVAL:(cntrB&0x1), 0, 0, true);
  		prm.L.set(errCode?EVAL:(cntrB&0x2), 0, 0, true);
  		prm.H.set(errCode?EVAL:(cntrB&0x4), 0, 0, true);
  		prm.cnt.set(prm.cnt.get()+1, 0, 0, true);
  	}

  	request = request.slice(6+blkLen);
  }

  return true;

OutPROG:
  JavaLikeCalc.JavaScript
  //Request form:
  //<mess addr="1" err="1:Error">{req}</mess> - message tag
  //  req - request/respond data;
  //  addr - remote station address (1...32);
  //  err - sets for the request result.
  io.setAttr("err", "");
  addr = io.attr("addr").toInt();
  if(addr < 1 || addr > 32) { io.setAttr("err","1:"+tr("Device address out of range 1...32")); return; }
  //Header
  reqHdr = SYS.strFromCharCode(0x16,0x03,addr,0x00);
  for(KS = 0, i = 1; i < reqHdr.length; i++)	KS += reqHdr.charCodeAt(i);
  KS = ~(KS+1);
  reqHdr += SYS.strFromCharCode(KS, KS>>8);
  //Body
  reqBody = io.text();
  for(KS = 0, i = 0; i < reqBody.length; i++)	KS += reqBody.charCodeAt(i);
  KS = ~(KS+1);
  reqBody += SYS.strFromCharCode(KS, KS>>8);
  request = reqHdr+reqBody;
  SYS.messDebug("/IT3/PRT",tr("Request")+": "+SYS.strDecode(request,"Bin"," "));

  //Send request
  resp = tr.messIO(request);
  while(resp.length) {
  	if(!(tresp=tr.messIO("")).length) break;
    	resp += tresp;
  }
  if(resp.length == 0) { io.setAttr("err","2:"+tr("No or short respond")); return; }
  SYS.messDebug("/IT3/PRT","Respond: "+SYS.strDecode(resp,"Bin"," "));
  for(blkOff = 0, blkLen = 0; blkOff < resp.length; blkOff += 6+blkLen) {
  	if(resp.charCodeAt(blkOff) != 0x16){ io.setAttr("err","3:"+tr("Header error")); return; }
  	for(KS = 0, i = (blkOff+1); i < (blkOff+4); i++) KS += resp.charCodeAt(i);
  	KS = (~(KS+1))&0xFFFF;
  	if(((resp.charCodeAt(blkOff+5)<<8)+resp.charCodeAt(blkOff+4)) != KS)
  	{ io.setAttr("err","3:"+tr("Header CRC error")); return; }
  	blkLen = resp.charCodeAt(blkOff+1);
  	if(blkOff+6+blkLen > resp.length) { io.setAttr("err","4:"+tr("Info block size error")); return; }
  	for(KS = 0, i = (blkOff+6); i < (blkOff+6+blkLen-2); i++) KS += resp.charCodeAt(i);
  	KS = (~(KS+1))&0xFFFF;
  	if(((resp.charCodeAt(blkOff+6+blkLen-1)<<8)+resp.charCodeAt(blkOff+6+blkLen-2)) != KS)
  	{ io.setAttr("err","4:"+tr("Info block CRC error.")); return; }
  	if(resp.charCodeAt(blkOff+6) == 0x80 && resp.charCodeAt(blkOff+7))
  	{ io.setAttr("err","5:"+resp.charCodeAt(blkOff+7)+":"+tr("Request error")); return; }
  	io.setText(resp.slice(blkOff+6,blkOff+6+blkLen));
  }


ID: IVE_452HS_02
NAME: ИВЭ-452HS-02
uk#NAME: IVE-452HS-02
DESCR:
  Protocol level of power supply of beam-electrons evaporator of "Plasma Tech" Ltd, from Moskov.
  Author: Roman Savochenko <rom_as@oscada.org>
  Sponsored: Vasiliy Grigoriev from "Vacuum technologies laboratory (http://e-beam.ru)".

OutPROG:
  JavaLikeCalc.JavaScript
  //Request form:
  //<mess addr="255" err="1:Error">{req}</mess> - message tag
  //  req - request/respond data;
  //  addr - remote station address (0...255);
  //  err - sets for the request result.
  io.setAttr("err", "");
  addr = io.attr("addr").toInt();
  if(addr < 0 || addr > 255) { io.setAttr("err","1:"+tr("Device address out of range 0...255")); return; }
  //Request prepare
  req = SYS.strFromCharCode(addr)+io.text();
  for(KS = 0, i = 0; i < req.length; i++)	KS += req.charCodeAt(i);
  KS = 0x100-KS&0xFF;
  req += SYS.strFromCharCode(KS);
  SYS.messDebug("/IVE452HS02/PRT",tr("Request")+": "+SYS.strDecode(req,"Bin"," "));

  //Send request
  resp = tr.messIO(req);
  while(resp.length) {
  	if(!(tresp=tr.messIO("")).length) break;
    	resp += tresp;
  }
  if(resp.length == 0) { io.setAttr("err","2:"+tr("No a respond")); return; }
  SYS.messDebug("/IVE452HS02/PRT","Respond: "+SYS.strDecode(resp,"Bin"," "));
  if(resp.length <= 3 || resp.charCodeAt(0) != addr || resp.charCodeAt(1) != req.charCodeAt(1))
  { io.setAttr("err","3:"+tr("Respond too short or wrong")); return; }
  for(KS = 0, i = 0; i < resp.length-1; i++)	KS += resp.charCodeAt(i);
  KS = 0x100-KS&0xFF;
  if(resp.charCodeAt(resp.length-1) != KS )	{ io.setAttr("err","3:"+tr("CRC error")); return; }
  io.setText(resp.slice(1,resp.length-1));


ID: OPTRIS
NAME: OPTRIS CT/CTL
DESCR:
  Protocol level of OPTRIS CT/CTL communication interface of "Optris" GmbH, from Berlin.
  Author: Roman Savochenko <rom_as@oscada.org>
  Sponsored: Vasiliy Grigoriev from "Vacuum technologies laboratory (http://e-beam.ru)".

OutPROG:
  JavaLikeCalc.JavaScript
  //Request form:
  //<mess addr="1" cs="1" err="1:Error">{req}</mess> - message tag
  //  req - request/respond data;
  //  addr - remote station address (0...15);
  //  cs - use control sum for SET commands [0,1]
  //  err - sets for the request result.
  io.setAttr("err", "");
  addr = io.attr("addr").toInt();
  if(addr < 0 || addr > 15) { io.setAttr("err", "1:"+tr("Device address out of range 0...15")); return; }
  request = SYS.strFromCharCode(0xB0+addr) + io.text();
  if(io.attr("cs").toInt()) {
  	for(CS = 0, i = 0; i < request.length; i++) CS += request.charCodeAt(i);
  	request += SYS.strFromCharCode(CS);
  }
  SYS.messDebug("/OPTRIS/PRT",tr("Request")+": "+SYS.strDecode(request,"Bin"," "));

  //Send request
  resp = tr.messIO(request);
  while(resp.length && (tresp=tr.messIO("")).length) resp += tresp;
  SYS.messDebug("/OPTRIS/PRT","Respond: "+SYS.strDecode(resp,"Bin"," "));
  if(resp.length <= 0) { io.setAttr("err","3:"+tr("No a respond")); return; }
  io.setText(resp);


ID: CTR
NAME: CTR 100, 101
uk#NAME: CTR 100, 101
DESCR:
  Protocol part of the RS232C Serial Interface permits the communication between the digital Oerlikon Leybold Vacuum CERAVAC, from Köln.
  Author: Roman Savochenko <rom_as@oscada.org>
  Sponsored: Vasiliy Grigoriev from "Vacuum technologies laboratory (http://e-beam.ru)".

uk#DESCR:
  Protocol part of the RS232C Serial Interface permits the communication between the digital Oerlikon Leybold Vacuum CERAVAC, from Köln.
  Author: Roman Savochenko <rom_as@oscada.org>
  Sponsored: Vasiliy Grigoriev from "Vacuum technologies laboratory (http://e-beam.ru)".

OutPROG:
  JavaLikeCalc.JavaScript
  //Request form:
  //<mess err="1:Error">{req}</mess> - message tag
  //  req - request/respond data;
  //  err - sets for the request result.
  io.setAttr("err", "");
  //Request prepare
  req = SYS.strFromCharCode(3) + io.text();
  for(CS = 0, i = 1; i < req.length; i++)	CS += req.charCodeAt(i);
  req += SYS.strFromCharCode(CS&0xFF);
  SYS.messDebug("/CTR/PRT",tr("Request")+": "+SYS.strDecode(req,"Bin"," "));

  //Send request
  for(resp = tr.messIO(req); resp.length < 9 && (tresp=tr.messIO("")).length; resp += tresp) ;
  if(resp.length == 0){ io.setAttr("err","2:"+tr("No a respond")); return; }
  SYS.messDebug("/CTR/PRT","Respond: "+SYS.strDecode(resp,"Bin"," "));
  if(resp.length < 9)	{ io.setAttr("err","3:"+tr("Respond too short")); return; }
  if(resp.length > 9)	{ io.setAttr("err","4:"+tr("Respond too long, possible continuous mode")); return; }
  for(CS = 0, i = 1; i < resp.length-1; i++)	CS += resp.charCodeAt(i);
  if(resp.charCodeAt(resp.length-1) != (CS&0xFF))	{ io.setAttr("err","5:"+tr("CRC error")); return; }
  io.setText(resp.slice(1,resp.length-1));


ID: SMTP
NAME: SMTP
uk#NAME: SMTP
DESCR:
  Provides EMAIL sending by the protocol SMTP.
  Author: Roman Savochenko <rom_as@oscada.org>
  Version: 1.0.0

uk#DESCR:
  Provides EMAIL sending by the protocol SMTP.
  Author: Roman Savochenko <rom_as@oscada.org>
  Version: 1.1.0

OutPROG:
  JavaLikeCalc.JavaScript
  //Request form:
  //<send auth="{user}:{pass}" from="{FromAddr}" to="{ToAddr}" topic="{My Topic}" err="1:Error">{MessageText}</send>
  //  topic - the message topic;
  //  from - sender address;
  //  to - destination address of the receiver;
  //  auth - authenticate user and password;
  //  MessageText - the message text;
  //  err - sets for the request result.

  //Transport's timings check
  if(tr.timings() != "5:1")	tr.timings("5:1");
  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 a response.")); return; }
  for(off = 0; (sit=rez.parse(0,"\x0D\x0A",off)).length; )
  	if(sit.toInt() != 250)	{ io.setAttr("err", "101:"+tr("HELLO error: %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 a 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 a 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 a 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 a 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 a 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 a 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 a 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);


ID: AT24CXX
NAME: I2C: AT24C{32|64}
DESCR:
  Provides operations with EEPROM memory based on I2C chips AT24C32 (4KB) and AT24C64 (8KB). Supported random reading and writing.
  Author: Roman Savochenko <rom_as@oscada.org>
  Version: 1.0.0

OutPROG:
  JavaLikeCalc.JavaScript
  //Request form:
  //<{cmd} addr="{ChipAddr}" off="{MemOffset}" size="{ReadSize}" err="1:Error">{ReadWriteSeq}</{cmd}>
  //  cmd - command, for now there allowed: "read", "write";
  //  addr - I2C device address [0...119];
  //  off - memory part offset;
  //  size - readed memory block size;
  //  ReadWriteSeq - Read/Write bytes sequence;
  //  err - sets for the request result.

  //Transport's timings check
  if(tr.timings() != "100:0.01")	tr.timings("100:0.01");
  addr = io.attr("addr").toInt();
  if(addr < 0 || addr > 119) { io.setAttr("err", "1:"+tr("Device address out of range 0...119.")); return; }
  off = io.attr("off").toInt();
  if(off < 0 || off >= 8192) { io.setAttr("err", "1:"+tr("Memory offset out of range 0...8191.")); return; }

  io.setAttr("err", "");

  if(io.name() == "read") {
  	size = io.attr("size").toInt();
  	if(size < 0 || size >= 8192) { io.setAttr("err", "2:"+tr("Readed memory size out of range 0...8191.")); return; }
  	resp = tr.messIO(SYS.strFromCharCode(addr,off>>8,off&0xFF), 0, size);
  	if(resp.length < size)	{ io.setAttr("err", "3:"+tr("Not or short respond %1 from %2.").replace("%1",resp.length.toString()).replace("%2",size.toString())); return; }
  	io.setText(resp);
  	return;
  }
  if(io.name() == "write") {
  	if(io.text().length >= 8192) { io.setAttr("err", "2:"+tr("Too long write sequence.")); return; }	
  	tr.messIO(SYS.strFromCharCode(addr,off>>8,off&0xFF)+io.text(), 0, 0);
  	return;
  }


ID: m200
NAME: Mercury 200
ru#NAME: Меркурий 200
DESCR:
  Protocol level of 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

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

OutPROG:
  JavaLikeCalc.JavaScript
  //resp="";
  //преобразуем сетевой адрес для запроса
  net0 ="0x"+io.attr("first").toInt(10).toString(16,2);
  net1 ="0x"+io.attr("second").toInt(10).toString(16,6).slice(0,2);
  net2 ="0x"+io.attr("second").toInt(10).toString(16,6).slice(2,4);
  net3 ="0x"+io.attr("second").toInt(10).toString(16,6).slice(4,6);
  request = SYS.strFromCharCode(Special.FLibSYS.str2int(net0),Special.FLibSYS.str2int(net1),Special.FLibSYS.str2int(net2),Special.FLibSYS.str2int(net3))+io.attr("data");
  //Вычисление CRC запроса
  out = 0xFFFF;
  for( i = 0; i < request.length; i++ )
  {
  out = out^request.charCodeAt(i);
  for( j=0; j<8; j++ ) out = (out&1) ? ((out>>1)^0xA001) : out >> 1;
  }
  CRC=SYS.strFromCharCode(out&0xFF,(out&0xFF00)>>8 );
  //запрос
  resp1 = tr.messIO(request+CRC);
  resp2 = tr.messIO("");
  resp3 = tr.messIO("");
  resp=(resp1+resp2+resp3);
  //Что есть ответ и что есть контрольная сумма
  answer=resp.slice(0,resp.length-2);
  CRCans=resp.slice(resp.length-2,resp.length);
  // Вычисление CRC ответа
  out1 = 0xFFFF;
  for( i1 = 0; i1 < answer.length; i1++ )
  {
  out1 = out1^answer.charCodeAt(i1);
  for( j1=0; j1<8; j1++ ) out1 = (out1&1) ? ((out1>>1)^0xA001) : out1 >> 1;
  }
  CRC1=SYS.strFromCharCode(out1&0xFF,(out1&0xFF00)>>8 );
  //Проверяем контрольную сумму  и принимаем ответ
  if((CRCans==CRC1)&&(request.charCodeAt(0)==answer.charCodeAt(0))&&(request.charCodeAt(1)==answer.charCodeAt(1))&&(request.charCodeAt(2)==answer.charCodeAt(2))&&(request.charCodeAt(3)==answer.charCodeAt(3)))//break;
  //k++;}
  io.setText(Special.FLibSYS.strDec4Bin(resp));

ru#OutPROG:
  JavaLikeCalc.JavaScript
  //resp="";
  //преобразуем сетевой адрес для запроса
  net0 ="0x"+io.attr("first").toInt(10).toString(16,2);
  net1 ="0x"+io.attr("second").toInt(10).toString(16,6).slice(0,2);
  net2 ="0x"+io.attr("second").toInt(10).toString(16,6).slice(2,4);
  net3 ="0x"+io.attr("second").toInt(10).toString(16,6).slice(4,6);
  request = SYS.strFromCharCode(Special.FLibSYS.str2int(net0),Special.FLibSYS.str2int(net1),Special.FLibSYS.str2int(net2),Special.FLibSYS.str2int(net3))+io.attr("data");
  //Вычисление CRC запроса
  out = 0xFFFF;
  for( i = 0; i < request.length; i++ )
  {
  out = out^request.charCodeAt(i);
  for( j=0; j<8; j++ ) out = (out&1) ? ((out>>1)^0xA001) : out >> 1;
  }
  CRC=SYS.strFromCharCode(out&0xFF,(out&0xFF00)>>8 );
  //запрос
  resp1 = tr.messIO(request+CRC);
  resp2 = tr.messIO("");
  resp3 = tr.messIO("");
  resp=(resp1+resp2+resp3);
  //Что есть ответ и что есть контрольная сумма
  answer=resp.slice(0,resp.length-2);
  CRCans=resp.slice(resp.length-2,resp.length);
  // Вычисление CRC ответа
  out1 = 0xFFFF;
  for( i1 = 0; i1 < answer.length; i1++ )
  {
  out1 = out1^answer.charCodeAt(i1);
  for( j1=0; j1<8; j1++ ) out1 = (out1&1) ? ((out1>>1)^0xA001) : out1 >> 1;
  }
  CRC1=SYS.strFromCharCode(out1&0xFF,(out1&0xFF00)>>8 );
  //Проверяем контрольную сумму  и принимаем ответ
  if((CRCans==CRC1)&&(request.charCodeAt(0)==answer.charCodeAt(0))&&(request.charCodeAt(1)==answer.charCodeAt(1))&&(request.charCodeAt(2)==answer.charCodeAt(2))&&(request.charCodeAt(3)==answer.charCodeAt(3)))//break;
  //k++;}
  io.setText(Special.FLibSYS.strDec4Bin(resp));


ID: m230
NAME: Mercury 230
ru#NAME: Меркурий 230
DESCR:
  Protocol level of 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

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

OutPROG:
  JavaLikeCalc.JavaScript
  //преобрауем сетевой адрес,преобразуем из строки в целое
  netaddr1 ="0x"+io.attr("netaddr").toInt(10).toString(16);
  request = SYS.strFromCharCode(Special.FLibSYS.str2int(netaddr1))+io.attr("data");
  //Вычисление CRC запроса
  out = 0xFFFF;
  for( i = 0; i < request.length; i++ )
  {
  out = out^request.charCodeAt(i);
  for( j=0; j<8; j++ ) out = (out&1) ? ((out>>1)^0xA001) : out >> 1;
  }
  CRC=SYS.strFromCharCode(out&0xFF,(out&0xFF00)>>8 );
  //Отправляем запрос
  //resp = tr.messIO(request+CRC);
  resp1 = tr.messIO(request+CRC);
  resp2 = tr.messIO("");
  resp3 = tr.messIO("");
  resp=(resp1+resp2+resp3);
  //Что есть ответ и что есть контрольная сумма
  answer=resp.slice(0,resp.length-2);
  CRCans=resp.slice(resp.length-2,resp.length);
  // Вычисление CRC ответа
  out1 = 0xFFFF;
  for( i1 = 0; i1 < answer.length; i1++ )
  {
  out1 = out1^answer.charCodeAt(i1);
  for( j1=0; j1<8; j1++ ) out1 = (out1&1) ? ((out1>>1)^0xA001) : out1 >> 1;
  }
  CRC1=SYS.strFromCharCode(out1&0xFF,(out1&0xFF00)>>8 );
  //Последовательность байт для интерпретации ответа
  b1 =Special.FLibSYS.strDec4Bin(resp.slice(1,2));
  b2 =Special.FLibSYS.strDec4Bin(resp.slice(2,3));
  b3 =Special.FLibSYS.strDec4Bin(resp.slice(3,4));
  b4 =Special.FLibSYS.strDec4Bin(resp.slice(4,5));
  b5 =Special.FLibSYS.strDec4Bin(resp.slice(5,6));
  b6 =Special.FLibSYS.strDec4Bin(resp.slice(6,7));
  b7 =Special.FLibSYS.strDec4Bin(resp.slice(7,8));
  b8 =Special.FLibSYS.strDec4Bin(resp.slice(8,9));
  b9 =Special.FLibSYS.strDec4Bin(resp.slice(9,10));
  b10 =Special.FLibSYS.strDec4Bin(resp.slice(10,11));
  b11 =Special.FLibSYS.strDec4Bin(resp.slice(11,12));
  b12 =Special.FLibSYS.strDec4Bin(resp.slice(12,13));
  b13 =Special.FLibSYS.strDec4Bin(resp.slice(13,14));
  b14 =Special.FLibSYS.strDec4Bin(resp.slice(14,15));
  b15 =Special.FLibSYS.strDec4Bin(resp.slice(15,16));
  b16 =Special.FLibSYS.strDec4Bin(resp.slice(16,17));
  //если контрольная сумма ответа совпадает и адрес ответа равен адресу запроса 
  if(CRCans==CRC1&&(request.charCodeAt(0)==answer.charCodeAt(0))/*&&answer.length>1*/ )
  //отклик от счетчика
  {
  if(request.charCodeAt(1)==0x01)
   io.setText(Special.FLibSYS.strDec4Bin(resp));
  //чтение энергии
  else if((request.charCodeAt(1)==0x05)&&(answer.length==17))
  {R1=b2+b1+b4+b3;R2=b6+b5+b8+b7;R3=b10+b9+b12+b11;R4=b14+b13+b16+b15;
   io.setText(R1.toInt(16).toString(10,10,)+R2.toInt(16).toString(10,10,)+R3.toInt(16).toString(10,10,)+R4.toInt(16).toString(10,10,));}

  //чтение напряжения U разом
  else if((request.charCodeAt(1)==0x08)&&(request.charCodeAt(2)==0x16)&&(request.charCodeAt(3)==0x11)&&(answer.length==10)) 
  {U1=b1+b3+b2;U2=b4+b6+b5;U3=b7+b9+b8;
  io.setText(U1.toInt(16).toString(10,8,)+U2.toInt(16).toString(10,8,)+U3.toInt(16).toString(10,8,));}
  //чтение Мощности P Q S разом
  else if((request.charCodeAt(1)==0x08)&&(request.charCodeAt(2)==0x16)&&(request.charCodeAt(3)==0x00||request.charCodeAt(3)==0x04||request.charCodeAt(3)==0x08)&&(answer.length==13)) 
  {PS=b1.slice(1,2)+b3+b2;P1=b4.slice(1,2)+b6+b5;P2=b7.slice(1,2)+b9+b8;P3=b10.slice(1,2)+b12+b11;
  io.setText(PS.toInt(16).toString(10,7,)+P1.toInt(16).toString(10,7,)+P2.toInt(16).toString(10,7,)+P3.toInt(16).toString(10,7,)+b1.slice(0,1)+b4.slice(0,1)+b7.slice(0,1)+b10.slice(0,1));}

  //чтение тока I разом
  else if((request.charCodeAt(1)==0x08)&&(request.charCodeAt(2)==0x16)&&(request.charCodeAt(3)==0x21)&&(answer.length==10)) 
  {I1=b1+b3+b2;I2=b4+b6+b5;I3=b7+b9+b8;
  io.setText(I1.toInt(16).toString(10,8,)+I2.toInt(16).toString(10,8,)+I3.toInt(16).toString(10,8,));}
  //чтение коэф.мощности
  else if((request.charCodeAt(1)==0x08)&&(request.charCodeAt(2)==0x16)&&(request.charCodeAt(3)==0x30)&&(answer.length==13)) 
  {KS=b1.slice(1,2)+b3+b2;K1=b4.slice(1,2)+b6+b5;K2=b7.slice(1,2)+b9+b8;K3=b10.slice(1,2)+b12+b11;
  io.setText(KS.toInt(16).toString(10,7,)+K1.toInt(16).toString(10,7,)+K2.toInt(16).toString(10,7,)+K3.toInt(16).toString(10,7,));}
  //чтение частоты F
  else if((request.charCodeAt(1)==0x08)&&(request.charCodeAt(2)==0x16)&&(request.charCodeAt(3)==0x40)&&(answer.length==4))
  {resp=b1+b3+b2;
   io.setText(resp.toInt(16).toString(10,,)/100);}
  //чтение серийного номера
  else if((request.charCodeAt(1)==0x08)&&(request.charCodeAt(2)==0x00)&&(answer.length==8))
   io.setText(b1.toInt(16).toString(10,2,)+b2.toInt(16).toString(10,2,)+b3.toInt(16).toString(10,2,)+b4.toInt(16).toString(10,2,));
  ;}

ru#OutPROG:
  JavaLikeCalc.JavaScript
  //преобрауем сетевой адрес,преобразуем из строки в целое
  netaddr1 ="0x"+io.attr("netaddr").toInt(10).toString(16);
  request = SYS.strFromCharCode(Special.FLibSYS.str2int(netaddr1))+io.attr("data");
  //Вычисление CRC запроса
  out = 0xFFFF;
  for( i = 0; i < request.length; i++ )
  {
  out = out^request.charCodeAt(i);
  for( j=0; j<8; j++ ) out = (out&1) ? ((out>>1)^0xA001) : out >> 1;
  }
  CRC=SYS.strFromCharCode(out&0xFF,(out&0xFF00)>>8 );
  //Отправляем запрос
  //resp = tr.messIO(request+CRC);
  resp1 = tr.messIO(request+CRC);
  resp2 = tr.messIO("");
  resp3 = tr.messIO("");
  resp=(resp1+resp2+resp3);
  //Что есть ответ и что есть контрольная сумма
  answer=resp.slice(0,resp.length-2);
  CRCans=resp.slice(resp.length-2,resp.length);
  // Вычисление CRC ответа
  out1 = 0xFFFF;
  for( i1 = 0; i1 < answer.length; i1++ )
  {
  out1 = out1^answer.charCodeAt(i1);
  for( j1=0; j1<8; j1++ ) out1 = (out1&1) ? ((out1>>1)^0xA001) : out1 >> 1;
  }
  CRC1=SYS.strFromCharCode(out1&0xFF,(out1&0xFF00)>>8 );
  //Последовательность байт для интерпретации ответа
  b1 =Special.FLibSYS.strDec4Bin(resp.slice(1,2));
  b2 =Special.FLibSYS.strDec4Bin(resp.slice(2,3));
  b3 =Special.FLibSYS.strDec4Bin(resp.slice(3,4));
  b4 =Special.FLibSYS.strDec4Bin(resp.slice(4,5));
  b5 =Special.FLibSYS.strDec4Bin(resp.slice(5,6));
  b6 =Special.FLibSYS.strDec4Bin(resp.slice(6,7));
  b7 =Special.FLibSYS.strDec4Bin(resp.slice(7,8));
  b8 =Special.FLibSYS.strDec4Bin(resp.slice(8,9));
  b9 =Special.FLibSYS.strDec4Bin(resp.slice(9,10));
  b10 =Special.FLibSYS.strDec4Bin(resp.slice(10,11));
  b11 =Special.FLibSYS.strDec4Bin(resp.slice(11,12));
  b12 =Special.FLibSYS.strDec4Bin(resp.slice(12,13));
  b13 =Special.FLibSYS.strDec4Bin(resp.slice(13,14));
  b14 =Special.FLibSYS.strDec4Bin(resp.slice(14,15));
  b15 =Special.FLibSYS.strDec4Bin(resp.slice(15,16));
  b16 =Special.FLibSYS.strDec4Bin(resp.slice(16,17));
  //если контрольная сумма ответа совпадает и адрес ответа равен адресу запроса 
  if(CRCans==CRC1&&(request.charCodeAt(0)==answer.charCodeAt(0))/*&&answer.length>1*/ )
  //отклик от счетчика
  {
  if(request.charCodeAt(1)==0x01)
   io.setText(Special.FLibSYS.strDec4Bin(resp));
  //чтение энергии
  else if((request.charCodeAt(1)==0x05)&&(answer.length==17))
  {R1=b2+b1+b4+b3;R2=b6+b5+b8+b7;R3=b10+b9+b12+b11;R4=b14+b13+b16+b15;
   io.setText(R1.toInt(16).toString(10,10,)+R2.toInt(16).toString(10,10,)+R3.toInt(16).toString(10,10,)+R4.toInt(16).toString(10,10,));}

  //чтение напряжения U разом
  else if((request.charCodeAt(1)==0x08)&&(request.charCodeAt(2)==0x16)&&(request.charCodeAt(3)==0x11)&&(answer.length==10)) 
  {U1=b1+b3+b2;U2=b4+b6+b5;U3=b7+b9+b8;
  io.setText(U1.toInt(16).toString(10,8,)+U2.toInt(16).toString(10,8,)+U3.toInt(16).toString(10,8,));}
  //чтение Мощности P Q S разом
  else if((request.charCodeAt(1)==0x08)&&(request.charCodeAt(2)==0x16)&&(request.charCodeAt(3)==0x00||request.charCodeAt(3)==0x04||request.charCodeAt(3)==0x08)&&(answer.length==13)) 
  {PS=b1.slice(1,2)+b3+b2;P1=b4.slice(1,2)+b6+b5;P2=b7.slice(1,2)+b9+b8;P3=b10.slice(1,2)+b12+b11;
  io.setText(PS.toInt(16).toString(10,7,)+P1.toInt(16).toString(10,7,)+P2.toInt(16).toString(10,7,)+P3.toInt(16).toString(10,7,)+b1.slice(0,1)+b4.slice(0,1)+b7.slice(0,1)+b10.slice(0,1));}

  //чтение тока I разом
  else if((request.charCodeAt(1)==0x08)&&(request.charCodeAt(2)==0x16)&&(request.charCodeAt(3)==0x21)&&(answer.length==10)) 
  {I1=b1+b3+b2;I2=b4+b6+b5;I3=b7+b9+b8;
  io.setText(I1.toInt(16).toString(10,8,)+I2.toInt(16).toString(10,8,)+I3.toInt(16).toString(10,8,));}
  //чтение коэф.мощности
  else if((request.charCodeAt(1)==0x08)&&(request.charCodeAt(2)==0x16)&&(request.charCodeAt(3)==0x30)&&(answer.length==13)) 
  {KS=b1.slice(1,2)+b3+b2;K1=b4.slice(1,2)+b6+b5;K2=b7.slice(1,2)+b9+b8;K3=b10.slice(1,2)+b12+b11;
  io.setText(KS.toInt(16).toString(10,7,)+K1.toInt(16).toString(10,7,)+K2.toInt(16).toString(10,7,)+K3.toInt(16).toString(10,7,));}
  //чтение частоты F
  else if((request.charCodeAt(1)==0x08)&&(request.charCodeAt(2)==0x16)&&(request.charCodeAt(3)==0x40)&&(answer.length==4))
  {resp=b1+b3+b2;
   io.setText(resp.toInt(16).toString(10,,)/100);}
  //чтение серийного номера
  else if((request.charCodeAt(1)==0x08)&&(request.charCodeAt(2)==0x00)&&(answer.length==8))
   io.setText(b1.toInt(16).toString(10,2,)+b2.toInt(16).toString(10,2,)+b3.toInt(16).toString(10,2,)+b4.toInt(16).toString(10,2,));
  ;}


# flb_doc

ID: getVal
NAME: Getting value from archive
uk#NAME: Запит значення архіву
ru#NAME: Запрос знач. архива
DESCR:
  Query the value for a specified time from the assigned archive and issuing the result with the specified number of decimal points.
  Author: Roman Savochenko <rom_as@oscada.org>
  Version: 1.1.0

uk#DESCR:
  Запит значення на визначений час з вказаного архіву та видача результату з вказаною кількістю знаків після точки.
  Автор: Роман Савоченко <rom_as@oscada.org>
  Версія: 1.1.0

ru#DESCR:
  Запрос значения на указанное время из установленного архива и выдача результата с указанным количеством знаков после точки.
  Автор: Роман Савоченко <rom_as@oscada.org>
  Версия: 1.1.0

FORMULA:
  srcTime = time*1e6 + uTime;
  aO = SYS.nodeAt(addr).arch();
  if(aO) {
  	if(!tryTo || tryTo == srcTime)	val = aO.getVal(srcTime, false, archtor);
  	else {
  		aPer = aO.period(archtor);
  		if(srcTime < tryTo)
  			for(srcTime1 = srcTime; srcTime < tryTo && (val=aO.getVal(srcTime1,false,archtor)).isEVal(); )
  			{ srcTime += aPer; srcTime1 = srcTime; }
  		else
  			for(srcTime1 = srcTime; srcTime > tryTo && (val=aO.getVal(srcTime1,false,archtor)).isEVal(); )
  			{ srcTime -= aPer; srcTime1 = srcTime; }
  	}
  	if(strong && (srcTime*1e-6) != time)	val = EVAL;
  } else val = EVAL;
  if(prec < 0)	return val;
  if(val.isEVal())	return tr("Empty");
  if(typeof(val) == "real")	return val.toFixed(prec);
  return val;


ID: sumVal
NAME: Sum values of archive
uk#NAME: Сума значень архіву
ru#NAME: Сумма знач. архива
DESCR:
  Calculating the sum of values ​​for a specified period of time an archive and issuing results with the specified number of decimal points.
  Author: Roman Savochenko <rom_as@oscada.org>
  Version: 1.1.0

uk#DESCR:
  Обчислення суми значень за проміжок часу визначеного архіву та видача результату з вказаною кількістю знаків після точки.
  Автор: Роман Савоченко <rom_as@oscada.org>
  Версія: 1.1.0

ru#DESCR:
  Вычисление суммы значений за промежуток времени указанного архива и выдача результата с указанным количеством знаков после точки.
  Автор: Роман Савоченко <rom_as@oscada.org>
  Версия: 1.1.0

FORMULA:
  val = 0;
  aO = SYS.nodeAt(addr).arch();
  if(aO) {
  	bTime = bTime*1e6; eTime = eTime*1e6;
  	buf_beg = max(aO.begin(archtor), bTime); buf_end = min(aO.end(archtor), eTime);
  	while(true) {
  		r_val = aO.getVal(buf_beg, true, archtor);
  		if(buf_beg > buf_end)	break;
  		if(!r_val.isEVal())	val += r_val;
  		if(buf_beg == 0 || buf_beg >= buf_end) break;
  		buf_beg++;
  	}
  }
  if(prec < 0)	return val;
  if(val.isEVal())	return tr("Empty");
  if(typeof(val) == "real")	return val.toFixed(prec);
  return val;


ID: averVal
NAME: Average value of archive
uk#NAME: Середнє значення архіву
ru#NAME: Среднее знач. архива
DESCR:
  Calculate the average value over a specified period of time an archive and issuing results with the specified number of decimal points.
  Author: Roman Savochenko <rom_as@oscada.org>
  Version: 1.1.0

uk#DESCR:
  Обчислення середнього значення за проміжок часу визначеного архіву та видача результату з вказаною кількістю знаків після точки.
  Автор: Роман Савоченко <rom_as@oscada.org>
  Версія: 1.1.0

ru#DESCR:
  Вычисление среднего значения за промежуток времени указанного архива и выдача результата с указанным количеством знаков после точки.
  Автор: Роман Савоченко <rom_as@oscada.org>
  Версия: 1.1.0

FORMULA:
  val = EVAL;
  actPerc = 0;
  aO = SYS.nodeAt(addr).arch();
  if(aO) {
  	bTime = bTime*1e6; eTime = eTime*1e6;
  	vCnt = (eTime-bTime)/aO.period(archtor)+1;
  	buf_beg = max(aO.begin(archtor), bTime); buf_end = min(aO.end(archtor), eTime);
  	for(vCntA = 0; true; ) {
    		buf_beg1 = buf_beg;
  		r_val = aO.getVal(buf_beg, true, archtor);
  		if(buf_beg > buf_end)	break;
  		if(!r_val.isEVal())	vCntA++;
  		if(val.isEVal())	val = r_val;
  		else if(!r_val.isEVal())
  			val = (val*(buf_beg-bTime) + r_val*(buf_beg-buf_beg1))/(buf_beg - bTime + buf_beg - buf_beg1);
  		if(buf_beg == 0 || buf_beg >= buf_end) break;
  		buf_beg++;
  	}
  	//SYS.messInfo("averVal", "vCntA="+vCntA+"("+vCnt+"); archtor="+archtor); 
  	actPerc = vCntA ? min(100,100*vCntA/vCnt) : 0;
  }
  if(prec < 0)	return val;
  if(val.isEVal())	return tr("Empty");
  if(typeof(val) == "real")	return val.toFixed(prec);
  return val;


