JavaLikeCalc.JavaScript
//Same request to the device
function req(tr, fnc, data, noRespData) {
	if(data == EVAL)	data = "";
	if(noRespData == EVAL)	noRespData = false;
	req = "#" + addr.toString(16) + fnc.toString(16) + data;
	//Calc and append the CRC
	for(CRC = 0x25, iR = 1; iR < req.length; iR++)	CRC = CRC^req.charCodeAt(iR);
	req += CRC.toString(16,2) + "\r";
	SYS.messDebug("/CorrBK/req", tr("Request")+": "+req.slice(0,-1));
	//tm_ = SYS.time(utm_);
	resp = tr.messIO(req);
	//Wait for an acceptance
	while(resp.length && (resp.length < 3 || resp.indexOf("\r") < 0) && (tresp=tr.messIO("")).length) resp += tresp;
	if(resp.length < 3 || (accEnd=resp.indexOf("\r")) < 0)
		return tr("3:No response or the response is incompleted. ");
	if(resp.slice(0,accEnd) != "%"+req.slice(1,3)+"OKEY")
		return tr("4:Not acceptable response '%1'.").replace("%1",resp.slice(0,accEnd));
	resp = resp.slice(accEnd+1);
	while((resp.length < 6 || resp[resp.length-1] != "\r") && (tresp=tr.messIO("")).length) resp += tresp;
	if(resp.length < 6 || resp[resp.length-1] != "\r")
		return tr("3:No response or the response incompleted. ");
	SYS.messDebug("/CorrBK/req", tr("Response")+": "+resp.slice(0,-1));
	if(noRespData)	{ data = resp.slice(3,-1); return "0"; }
	//Calc and check the CRC
	for(CRC = 0x25, iR = 1; iR < resp.length-3; iR++)	CRC = CRC^resp.charCodeAt(iR);
	if(CRC != resp.slice(-3).toInt(16))	return tr("3:Error the response CRC. ");

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

	return "0";
}

//Parse float
function floatGet(str) {
	X = new Array();
	isZero = true;
	for(iB = 0; iB < 4; iB++) {
		X[iB] = str.slice(iB*2,2+iB*2).toInt(16);
		if(isZero && X[iB])	isZero = false;
	}
	if(isZero)	return 0;
	sign = (X[0] > 127); X[0] = X[0] | 0x80;
	rez = pow(2,X[1]-127) * (X[0]*pow(2,16) + X[3]*pow(2,8) + X[2]) / pow(2,24);
	return sign ? -rez : rez;
}
//Produce float
function floatSet(vl) {
	exp = 0;
	while(vl/pow(2,exp) > 1 && exp < 128)		exp++;
	while(vl/pow(2,exp) < 0.5 && exp > -127)exp--;
	mts = (vl/pow(2,exp))*pow(2,24) + 0.5;
	if(vl >= 0) mts = mts&0x7FFFFF;
	return ((mts>>16)&0xFF).toString(16,2)+(exp+127).toString(16,2)+(mts&0xFFFF).toString(16,4);
}

//Set value to the archive
function archSet(attr, vTm, arh, vl) {
	SYS.messDebug("/CorrBK/archSet","attr="+attr+"; vTm="+SYS.strftime(vTm)+"; arh="+arh+"; vl="+vl);
	atrO = this[attr];
	if(!atrO || atrO.isEVal()) return;
	arguments[attr] = vl;	//Set the current value
	//if(vTm > atrO.time())	atrO.set(vl,vTm,0,true);
	if(atrO.arch())	atrO.arch().setVal(vTm*1e6, vl, arh);
}

//Item of the archive processing:
// read value by the position, validate and write to the atribute's archive in the archivator's part
function archItPrc(tr, aO) {
	pos = (aO.initPos < aO.cnt) ? aO.initPos : aO.pos;
	tmCur = SYS.time();
	//  Read and check header of the item
	data = (aO.beg+(pos*aO.itSz)).toString(16,4)+"00000000";
	if((t_err=req(tr,6,data)).toInt())	return t_err;

	if(aO.id == "Alarms") {
		dtY = 2018; dtM = dtM_ = data.slice(0,2).toInt(10); dtD = data.slice(2,4).toInt(10); dtH = data.slice(4,6).toInt(10); dtMin = data.slice(6,8).toInt(10);
		dtTm_ = SYS.mktime(0, dtMin, dtH, dtD, dtM-1, dtY);
		SYS.localtime(tmCur, 0, 0, 0, 0, dtM_, dtY);
		if(dtM > dtM_)	dtY--;

		SYS.messDebug("/CorrBK/archItPrc", aO.id+": pos="+pos+"; dtY="+dtY+"; dtM="+dtM+"; dtD="+dtD+"; dtH="+dtH+"; dtMin="+dtMin+"; dtTm="+dtTm_);

		if(dtM < 1 || dtM > 12 || dtD < 1 || dtD > 31 || floor(dtTm_/aO.per) > floor(tmCur/aO.per))
			return "10:Date or time of the item is wrong";
		SYS.messDebug("/CorrBK/archItPrc", aO.id+": dtTm="+dtTm_+"; aO.tm="+aO.tm+"; aO.pos="+aO.pos);
		//  Mark the item as a candidate to current/last point
		if(dtTm_ > aO.tm) {
			aO.tm = dtTm_;
			if((aO.pos=pos+1) >= aO.cnt) aO.pos = 0;
		}
		aCode = data.slice(8,12).toInt(16);
		data = (aO.beg+(pos*aO.itSz)+6).toString(16,4)+"00000000";
		if((t_err=req(tr,6,data)).toInt())	return t_err;
		aValue = floatGet(data);
		SYS.messDebug("/CorrBK/archItPrc", aO.id+": code="+aCode+"; value="+aValue);
		// For an alarm message
		SYS.Archive.messPut(dtTm_, 0, "alCorBK:"+this.cntr().cfg("ID")+"."+this.cfg("SHIFR"), 3, "Alarm : " + aCode + " : " + aValue, aO.arh);
	}
	else {
		dtY = 2000 + data.slice(0,2).toInt(10); dtM = data.slice(2,4).toInt(10); dtD = data.slice(4,6).toInt(10); dtH = data.slice(6,8).toInt(10);
		dtTm_ = (aO.per >= 24*3600) ? SYS.timegm(0, 0, dtH, dtD, dtM-1, dtY) : SYS.mktime(0, 0, dtH, dtD, dtM-1, dtY);

		SYS.messDebug("/CorrBK/archItPrc", aO.id+": pos="+pos+"; dtY="+dtY+"; dtM="+dtM+"; dtD="+dtD+"; dtH="+dtH+"; dtTm="+dtTm_);

		if(dtM < 1 || dtM > 12 || dtD < 1 || dtD > 31 || floor(dtTm_/aO.per) > floor(tmCur/aO.per) || 
				(aO.initPos < aO.cnt && dtTm_ < (tmCur-aO.cnt*aO.per)))
//				((aO.initPos < aO.cnt && dtTm_ < (tmCur-aO.cnt*aO.per)) || dtTm_ <= aO.tm))
			return "10:Date or time of the item is wrong";
		//  Mark the item as a candidate to current/last point
		SYS.messDebug("/CorrBK/archItPrc", aO.id+": dtTm="+dtTm_+"; aO.tm="+aO.tm+"; aO.pos="+aO.pos);
		if(dtTm_ > aO.tm) {
			aO.tm = dtTm_;
			if((aO.pos=pos+1) >= aO.cnt) aO.pos = 0;
		}
		archSet(aO.attrs[0], dtTm_, aO.arh, floatGet(data.slice(8)));
		for(iA = 1; iA < aO.attrs.length; iA += 2) {
			data = (aO.beg+(pos*aO.itSz)+8*(iA+1)/2).toString(16,4)+"00000000";
			if((t_err=req(tr,6,data)).toInt())	return t_err;
			archSet(aO.attrs[iA], dtTm_, aO.arh, floatGet(data));
			if((iA+1) < aO.attrs.length)
				archSet(aO.attrs[iA+1], dtTm_, aO.arh, floatGet(data.slice(8)));
		}
	}
	return "";
}

//Main process
// Set transport and init it
if(f_start) {
	f_err = "0:"+tr("Waiting for the full call");
	transport_ = transport;
	tr = SYS.Transport.nodeAt(transport, ".");
	devSt = ""; aSt = EVAL_INT; arhSt = "";
	cTm = 0;
	dtTm = EVAL;
	motoHours = EVAL;
	vWork = vAccWork = vResult = vAccResult = p = t = pFact = fWork = fResult = EVAL;
	stN2 = stN2_ = stCO2 = stCO2_ = stQ = stQ_ = stBP = stBP_ = stSubPL = stSubPL_
			= stSubPH = stSubPH_ = stSubT = stSubT_ = stFH = stFH_ = stFL = stFL_
			= stSubFL = stSubFL_ = stSubFH = stSubFH_ = EVAL;
	reset = false;
}

if((f_start && typeof(arhs) != "array") || reset) {
	reset = false;
	//Archives init
	tmCur = SYS.time();
	arhs = new Array();
	a = new Object();
	a.id = "Hours"; a.beg = 0x0136; a.itSz = 20; a.cnt = 1080; a.per = 3600;
	a.arh = arhH; a.attrs = new Array("p", "t", "vWork", "vResult");
	a.pos = 0; a.tm = 0; a.aTm = tmCur; a.initPos = 0;
	arhs.push(a);
	a = new Object();
	a.id = "Days"; a.beg = 0x5596; a.itSz = 28; a.cnt = 100; a.per = 24*3600;
	a.arh = arhD; a.attrs = new Array("p", "t", "vWork", "vResult", "vAccWork", "vAccResult");
	a.pos = 0; a.tm = 0; a.aTm = tmCur; a.initPos = 0;
	arhs.push(a);
	a = new Object();
	a.id = "Months"; a.beg = 0x6086; a.itSz = 20; a.cnt = 25; a.per = 31*24*3600;
	a.arh = arhM; a.attrs = new Array("vWork", "vResult", "vAccWork", "vAccResult");
	a.pos = 0; a.tm = 0; a.aTm = tmCur; a.initPos = 0;
	arhs.push(a);
	a = new Object();
	a.id = "Alarms"; a.beg = 0x627A; a.itSz = 10; a.cnt = 300; a.per = 60;
	a.arh = arhAlrm;
	a.pos = 0; a.tm = 0; a.aTm = tmCur; a.initPos = 0;
	arhs.push(a);
}
if(f_start || f_stop) return;

t_err = "0:";

//Check for the transport change and connect
if(!tr || transport != transport_)	{
	tr = SYS.Transport.nodeAt(transport, ".");
	transport_ = transport;
}
if(!tr)	t_err = "1:"+tr("Output transport '%1' error.").replace("%1",transport);
else if(addr < 0 || addr > 15)
	t_err = "2:"+tr("Address '%1' out of range [0...15].").replace("%1",addr.toString());
else {
	tmCur = SYS.time();
	//Settings write
	// Concentration N2
	if(!stN2.isEVal() && stN2 != stN2_ && !t_err.toInt()) {
		data = "6E36" + floatSet(stN2);
		if(!(t_err=req(tr,15,data,true)).toInt() && data == "OKEY")	stN2_ = stN2;
	}
	// Concentration CO2
	if(!stCO2.isEVal() && stCO2 != stCO2_ && !t_err.toInt()) {
		data = "6E3A" + floatSet(stCO2);
		if(!(t_err=req(tr,15,data,true)).toInt() && data == "OKEY")	stCO2_ = stCO2;
	}
	// Gas density
	if(!stQ.isEVal() && stQ != stQ_ && !t_err.toInt()) {
		data = "6E3E" + floatSet(stQ);
		if(!(t_err=req(tr,15,data,true)).toInt() && data == "OKEY")	stQ_ = stQ;
	}
	// Barometric pressure
	if(!stBP.isEVal() && stBP != stBP_ && !t_err.toInt()) {
		data = "6E42" + floatSet(stBP);
		if(!(t_err=req(tr,15,data,true)).toInt() && data == "OKEY")	stBP_ = stBP;
	}
	// Pressure substitution for lower border
	if(!stSubPL.isEVal() && stSubPL != stSubPL_ && !t_err.toInt()) {
		data = "6E46" + floatSet(stSubPL);
		if(!(t_err=req(tr,15,data,true)).toInt() && data == "OKEY")	stSubPL_ = stSubPL;
	}
	// Pressure substitution for high border
	if(!stSubPH.isEVal() && stSubPH != stSubPH_ && !t_err.toInt()) {
		data = "6E4A" + floatSet(stSubPH);
		if(!(t_err=req(tr,15,data,true)).toInt() && data == "OKEY")	stSubPH_ = stSubPH;
	}
	// Temperature substitution
	if(!stSubT.isEVal() && stSubT != stSubT_ && !t_err.toInt()) {
		data = "6E4E" + floatSet(stSubT);
		if(!(t_err=req(tr,15,data,true)).toInt() && data == "OKEY")	stSubT_ = stSubT;
	}
	// Flow maximum
	if(!stFH.isEVal() && stFH != stFH_ && !t_err.toInt()) {
		data = "6E52" + floatSet(stFH);
		if(!(t_err=req(tr,15,data,true)).toInt() && data == "OKEY")	stFH_ = stFH;
	}
	// Flow minimum
	if(!stFL.isEVal() && stFL != stFL_ && !t_err.toInt()) {
		data = "6E56" + floatSet(stFL);
		if(!(t_err=req(tr,15,data,true)).toInt() && data == "OKEY")	stFL_ = stFL;
	}
	// Flow substitution for lower border
	if(!stSubFL.isEVal() && stSubFL != stSubFL_ && !t_err.toInt()) {
		data = "6E5A" + floatSet(stSubFL);
		if(!(t_err=req(tr,15,data,true)).toInt() && data == "OKEY")	stSubFL_ = stSubFL;
	}
	// Flow substitution for high border
	if(!stSubFH.isEVal() && stSubFH != stSubFH_ && !t_err.toInt()) {
		data = "6E5E" + floatSet(stSubFH);
		if(!(t_err=req(tr,15,data,true)).toInt() && data == "OKEY")	stSubFH_ = stSubFH;
	}

	//Settings read
	// Concentration N2 and CO2
	data = "6E3600000000";
	if(!t_err.toInt() && (stN2.isEVal() || stCO2.isEVal()) && !(t_err=req(tr,6,data)).toInt()) {
		stN2 = stN2_ = floatGet(data);
		stCO2 = stCO2_ = floatGet(data.slice(8));
	}
	// Gas density and Barometric pressure
	data = "6E3E00000000";
	if(!t_err.toInt() && (stQ.isEVal() || stBP.isEVal()) && !(t_err=req(tr,6,data)).toInt()) {
		stQ = stQ_ = floatGet(data);
		stBP = stBP_ = floatGet(data.slice(8));
	}
	// Pressure substitution for lower and high border
	data = "6E4600000000";
	if(!t_err.toInt() && (stSubPL.isEVal() || stSubPH.isEVal()) && !(t_err=req(tr,6,data)).toInt()) {
		stSubPL = stSubPL_ = floatGet(data);
		stSubPH = stSubPH_ = floatGet(data.slice(8));
	}
	// Temperature substitution and Flow maximum
	data = "6E4E00000000";
	if(!t_err.toInt() && (stSubT.isEVal() || stFH.isEVal()) && !(t_err=req(tr,6,data)).toInt()) {
		stSubT = stSubT_ = floatGet(data);
		stFH = stFH_ = floatGet(data.slice(8));
	}
	// Flow minimum and Flow substitution for lower border
	data = "6E5600000000";
	if(!t_err.toInt() && (stFL.isEVal() || stSubFL.isEVal()) && !(t_err=req(tr,6,data)).toInt()) {
		stFL = stFL_ = floatGet(data);
		stSubFL = stSubFL_ = floatGet(data.slice(8));
	}
	// Flow substitution for high border
	data = "6E5E00000000";
	if(!t_err.toInt() && stSubFH.isEVal() && !(t_err=req(tr,6,data)).toInt())
		stSubFH = stSubFH_ = floatGet(data);

	//Current values request
	if(curRegul && (tmCur-cTm) > arhTryPer) {
		dtTm = motoHours = vWork = vResult = aSt = t = p = pFact = fWork = fResult = EVAL;
		cTm = tmCur;
	}
	// Date and time
	data = "036A00000000";
	if(dtTm.isEVal() && !t_err.toInt() && !(t_err=req(tr,5,data)).toInt()) {
		dtTm =	data.slice(0,2).toInt(10).toString() + "-" + data.slice(2,4).toInt(10).toString() + "-" + data.slice(4,6).toInt(10).toString() +
					"T" + data.slice(6,8).toInt(10).toString() + ":" + data.slice(8,10).toInt(10).toString();
		dtTm = SYS.strptime(dtTm, "%y-%m-%dT%H:%M").toString() + ": " + dtTm;
	}
	// Moto-hours
	data = "020A00000000";
	if(motoHours.isEVal() && !t_err.toInt() && !(t_err=req(tr,5,data)).toInt())
		motoHours = data.slice(0,4).toInt(16);
	// Volume: work and result
	data = "021000000000";
	if(vWork.isEVal() && !t_err.toInt() && !(t_err=req(tr,5,data)).toInt()) {
		vWork = floatGet(data);
		vResult = floatGet(data.slice(8));
	}
	// Alarms
	data = "022200000000";
	if(aSt.isEVal() && !t_err.toInt() && !(t_err=req(tr,5,data)).toInt()) {
		aSt = data.slice(0,4).toInt(16);
		devSt = aSt.toString()+": ";
		if(aSt&0x01)	devSt += "Er 0300; ";
		if(aSt&0x02)	devSt += "Er 0100; ";
		if(aSt&0x08)	devSt += "Er 0200; ";
		if(aSt&0x10)	devSt += "Er 2000; ";
		if(aSt&0x20)	devSt += "Er 1000; ";
		if(aSt&0x40)	devSt += "Er 3000; ";
		if(aSt&0x80)	devSt += "Er 4000; ";
		if(aSt&0x100)	devSt += "Er 0002; ";
		if(aSt&0x400)	devSt += "Er 0001; ";
		if(aSt&0x1000)devSt += "Er 0010; ";
		if(aSt&0x2000)devSt += "Er 0030; ";
		if(aSt&0x4000)devSt += "Er 0020; ";
		if(aSt&0x8000)devSt += "Er 0003; ";
		//SYS.messInfo("/CorrBK","aSt: "+aSt+"; devSt: "+devSt);
	}
	// Temperature, Pressure
	data = "024C00000000";
	if(t.isEVal() && !t_err.toInt() && !(t_err=req(tr,5,data)).toInt()) {
		t = floatGet(data);
		p = floatGet(data.slice(8));
	}
	// Pressing factor
	data = "025C00000000";
	if(pFact.isEVal() && !t_err.toInt() && !(t_err=req(tr,5,data)).toInt())
		pFact = floatGet(data);
	// Flow: work and resume
	data = "029800000000";
	if(fWork.isEVal() && !t_err.toInt() && !(t_err=req(tr,5,data)).toInt()) {
		fWork = floatGet(data);
		fResult = floatGet(data.slice(8));
	}

	//Archives array processing
	arhSt = "";
	for(iA = 0; iA < arhs.length; iA++) {
		aO = arhs[iA];
		arhSt += (arhSt.length?"; ":"")+aO.id + ": ";
		if(!aO.arh.length)	{ arhSt += tr("Disabled"); continue; }
		if(t_err.toInt())	arhSt += tr("Missed by error - ");
		// Check for the last value
		if(!t_err.toInt()) {
			if(aO.initPos >= aO.cnt && (tmCur-aO.aTm) > arhTryPer)
				while((SYS.time()-tmCur) < arhTmLim) {
					if((t_err1=archItPrc(tr,aO)).toInt() && t_err1.toInt() != 10)	t_err = t_err1;
					else aO.aTm = (iA && (tmCur-arhs[iA-1].aTm) < arhTryPer) ? arhs[iA-1].aTm : tmCur;
					if(t_err1.toInt())	break;
				}
			else while(aO.initPos < aO.cnt && (SYS.time()-tmCur) < arhTmLim) {
				if(aO.initPos < 0)	{ aO.initPos++; break; }
				SYS.messDebug("/CorrBK/archInit", aO.id+": initPos="+aO.initPos+"; pos="+aO.pos);
				if((t_err1=archItPrc(tr,aO)).toInt() && t_err1.toInt() != 10)	{ t_err = t_err1; break; }
				aO.initPos++;
				//  Miss the invalid item and re-check after some cycles, after an hour
				//if(t_err1.toInt() && aO.initPos >= aO.cnt && !aO.tm)	aO.initPos = -arhTryPer*f_frq;	//????
			}
		}
		if(aO.per > 24*3600)	dtForm = "%Y-%m";
		else if(aO.per > 3600)	dtForm = "%Y-%m-%d";
		else if(aO.per > 60)	dtForm = "%Y-%m-%d %H";
		else							dtForm = "%Y-%m-%d %H %M";
		if(aO.initPos >= aO.cnt) arhSt += tr("Trace for current in pos=%1, last=%2")
				.replace("%1",aO.pos.toString()).replace("%2",SYS.strftime(aO.tm,dtForm));
		else arhSt += tr("Initial scan in pos=%1(%4), near pos=%2, time=%3")
				.replace("%1",aO.initPos.toString())
				.replace("%4",aO.cnt.toString())
				.replace("%2",aO.pos.toString())
				.replace("%3",SYS.strftime(aO.tm,dtForm));
		SYS.cntrReq(SYS.XMLNode("save").setAttr("path",this.nodePath()+"/%2fobj").setAttr("force",1));
	}

	tmPrev = tmCur;
}

if(!t_err.toInt())	t_err = "0";
f_err = t_err+arhSt;