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

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

	return reqO.attr("err");
}

//Seting value to the archive
function archSet(attr, vTm, arh, vl) {
	SYS.messDebug("/GB/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);
}

//Main process
if(f_start) {
	f_err = "0:"+tr("Waiting for the full call");
	transport_ = transport;
	tr = EVAL;
	aStStr = ""; aSt = EVAL_INT; arhSt = "";
	cTm = 0;
	devManuf = devNameVer = devSN = curTm = arhStart = arhStart_ = arhLastH = arhLastD = arhLastM = EVAL;
	batV = batMinV = baseL = baseD = sndSpd = p = t = flowSpd = cntH = coefCompr = notWorkTm = vAccWork = vAccResult = vWork = vResult = fWork = fResult = 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.func = 65; a.cnt = 3840; a.per = 3600; a.arh = arhH; a.tm = 0;
	arhs.push(a);
	a = new Object();
	a.id = "Days"; a.func = 66; a.cnt = 3200; a.per = 24*3600; a.arh = arhD; a.tm = 0;
	arhs.push(a);
	a = new Object();
	a.id = "Months"; a.func = 67; a.cnt = 3200; a.per = 31*24*3600; a.arh = arhM; a.tm = 0;
	arhs.push(a);

	arhLastH = arhLastD = arhLastM = EVAL;
}
if(f_start || f_stop) return;

t_err = "0:";

//Check for the transport change and connect
//Check for the transport change and connect
if(tr.isEVal() || transport != transport_)	{
	if(!transport.length) {
		if(this.cntr().cfg("PROT") != "RTU")
			t_err = "1:"+tr("Output transport is empty and the controller object is not ModBus RTU.");
		else tr = new Object();
	}
	else tr = SYS.Transport[transport.parse(0)]["out_"+transport.parse(1)];
	transport_ = transport;
}
if(t_err.toInt()) ;
else if(tr.isEVal())
	t_err = "1:"+tr("Output transport '%1' error.").replace("%1",transport);
else if(addr < 0 || addr > 247)
	t_err = "2:"+tr("Address '%1' out of range [0...247].").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;
	}*/

	//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));
	}*/

	//Current values request
	if((tmCur-cTm) > arhTryPer) {
		devManuf = devNameVer = devSN = curTm = arhStart = arhStart_ = arhLastH = arhLastD = arhLastM = EVAL;
		batV = batMinV = baseL = baseD = sndSpd = p = t = flowSpd = cntH = coefCompr = notWorkTm = vAccWork = vAccResult = vWork = vResult = fWork = fResult = EVAL;
		cTm = tmCur;
	}
	// Device information
	data = SYS.strFromCharCode(0x11);
	if(devManuf.isEVal() && !t_err.toInt() && !(t_err=req(data)).toInt()) {
		doff = 2;
		devManuf = data.parse(0,"\000",doff);
		devNameVer = data.parse(0,"\000",doff);
		devSN = data.parse(0,"\000",doff);
	}
	// Battery voltage
	data = SYS.strFromCharCode(0x3, 0, 0xA, 0, 2);
	if(batV.isEVal() && !t_err.toInt() && !(t_err=req(data)).toInt())
		batV = SYS.Special.FLibSYS.floatMergeWord(data.charCodeAt(2,"UTF-16BE"), data.charCodeAt(4,"UTF-16BE"));
	// Battery minimum voltage
	data = SYS.strFromCharCode(0x3, 0, 0xC, 0, 2);
	if(batMinV.isEVal() && !t_err.toInt() && !(t_err=req(data)).toInt())
		batMinV = SYS.Special.FLibSYS.floatMergeWord(data.charCodeAt(2,"UTF-16BE"), data.charCodeAt(4,"UTF-16BE"));
	// Base length
	data = SYS.strFromCharCode(0x3, 0, 0x10, 0, 2);
	if(baseL.isEVal() && !t_err.toInt() && !(t_err=req(data)).toInt())
		baseL = SYS.Special.FLibSYS.floatMergeWord(data.charCodeAt(2,"UTF-16BE"), data.charCodeAt(4,"UTF-16BE"));
	// Base diameter
	data = SYS.strFromCharCode(0x3, 0, 0x12, 0, 2);
	if(baseD.isEVal() && !t_err.toInt() && !(t_err=req(data)).toInt())
		baseD = SYS.Special.FLibSYS.floatMergeWord(data.charCodeAt(2,"UTF-16BE"), data.charCodeAt(4,"UTF-16BE"));
	// Sound speed
	data = SYS.strFromCharCode(0x3, 0, 0x14, 0, 2);
	if(sndSpd.isEVal() && !t_err.toInt() && !(t_err=req(data)).toInt())
		sndSpd = SYS.Special.FLibSYS.floatMergeWord(data.charCodeAt(2,"UTF-16BE"), data.charCodeAt(4,"UTF-16BE"));
	// Flow speed
	data = SYS.strFromCharCode(0x3, 0, 0x1A, 0, 2);
	if(flowSpd.isEVal() && !t_err.toInt() && !(t_err=req(data)).toInt())
		flowSpd = SYS.Special.FLibSYS.floatMergeWord(data.charCodeAt(2,"UTF-16BE"), data.charCodeAt(4,"UTF-16BE"));
	// Gas P
	data = SYS.strFromCharCode(0x3, 0, 0x1C, 0, 2);
	if(p.isEVal() && !t_err.toInt() && !(t_err=req(data)).toInt())
		p = SYS.Special.FLibSYS.floatMergeWord(data.charCodeAt(2,"UTF-16BE"), data.charCodeAt(4,"UTF-16BE"));
	// Gas T
	data = SYS.strFromCharCode(0x3, 0, 0x1E, 0, 2);
	if(t.isEVal() && !t_err.toInt() && !(t_err=req(data)).toInt())
		t = SYS.Special.FLibSYS.floatMergeWord(data.charCodeAt(2,"UTF-16BE"), data.charCodeAt(4,"UTF-16BE"));
	// Coefficient of the compression
	data = SYS.strFromCharCode(0x3, 0, 0x20, 0, 2);
	if(coefCompr.isEVal() && !t_err.toInt() && !(t_err=req(data)).toInt())
		coefCompr = SYS.Special.FLibSYS.floatMergeWord(data.charCodeAt(2,"UTF-16BE"), data.charCodeAt(4,"UTF-16BE"));
	// Not work time
	data = SYS.strFromCharCode(0x3, 0, 0x22, 0, 1);
	if(notWorkTm.isEVal() && !t_err.toInt() && !(t_err=req(data)).toInt())
		notWorkTm = data.charCodeAt(2);
	// Volume: accumulated work
	data = SYS.strFromCharCode(0x3, 0x1, 0x00, 0, 2);
	if(vAccWork.isEVal() && !t_err.toInt() && !(t_err=req(data)).toInt())
		vAccWork = data.charCodeAt(2,"UTF-32BE");
	// Volume: accumulated resume
	data = SYS.strFromCharCode(0x3, 0x1, 0x02, 0, 2);
	if(vAccResult.isEVal() && !t_err.toInt() && !(t_err=req(data)).toInt())
		vAccResult = data.charCodeAt(2,"UTF-32BE");
	// Flow: work
	data = SYS.strFromCharCode(0x3, 0x1, 0x04, 0, 2);
	if(fWork.isEVal() && !t_err.toInt() && !(t_err=req(data)).toInt())
		fWork = SYS.Special.FLibSYS.floatMergeWord(data.charCodeAt(2,"UTF-16BE"), data.charCodeAt(4,"UTF-16BE"));
	// Flow: resume
	data = SYS.strFromCharCode(0x3, 0x1, 0x06, 0, 2);
	if(fResult.isEVal() && !t_err.toInt() && !(t_err=req(data)).toInt())
		fResult = SYS.Special.FLibSYS.floatMergeWord(data.charCodeAt(2,"UTF-16BE"), data.charCodeAt(4,"UTF-16BE"));

	// Current time
	data = SYS.strFromCharCode(0x3, 0x1, 0x10, 0, 3);
	if(curTm.isEVal() && !t_err.toInt() && !(t_err=req(data)).toInt())
		curTm = (data.charCodeAt(2+5)+2000).toString()+"-"+data.charCodeAt(2+4).toString(10,2)+"-"+data.charCodeAt(2+3).toString(10,2)+"T"+data.charCodeAt(2+2)+":"+data.charCodeAt(2+1).toString(10,2)+":"+data.charCodeAt(2+0).toString(10,2);
	// Archive begin
	data = SYS.strFromCharCode(0x3, 0x1, 0x13, 0, 3);
	if(arhStart.isEVal() && !t_err.toInt() && !(t_err=req(data)).toInt()) {
		dtY = data.charCodeAt(2+5)+2000; dtM = data.charCodeAt(2+4); dtD = data.charCodeAt(2+3); dtH = data.charCodeAt(2+2);
		arhStart_ = SYS.mktime(0, 0, dtH, dtD, dtM-1, dtY);
		arhStart = dtY.toString()+"-"+dtM.toString(10,2)+"-"+dtD.toString(10,2)+"T"+dtH+":"+data.charCodeAt(2+1).toString(10,2)+":"+data.charCodeAt(2+0).toString(10,2);
	}
	// Archive last hour
	data = SYS.strFromCharCode(0x3, 0x1, 0x16, 0, 3);
	if(arhLastH.isEVal() && !t_err.toInt() && !(t_err=req(data)).toInt()) {
		dtY = data.charCodeAt(2+5)+2000; dtM = data.charCodeAt(2+4); dtD = data.charCodeAt(2+3); dtH = data.charCodeAt(2+2);
		arhs[0].tmLast = SYS.mktime(0, 0, dtH, dtD, dtM-1, dtY);
		arhLastH = dtY.toString()+"-"+dtM.toString(10,2)+"-"+dtD.toString(10,2)+"T"+dtH+":"+data.charCodeAt(2+1).toString(10,2)+":"+data.charCodeAt(2+0).toString(10,2);
	}
	// Archive last day
	data = SYS.strFromCharCode(0x3, 0x1, 0x19, 0, 3);
	if(arhLastD.isEVal() && !t_err.toInt() && !(t_err=req(data)).toInt()) {
		dtY = data.charCodeAt(2+5)+2000; dtM = data.charCodeAt(2+4); dtD = data.charCodeAt(2+3); dtH = data.charCodeAt(2+2);
		arhs[1].tmLast = SYS.mktime(0, 0, dtH, dtD, dtM-1, dtY);
		arhLastD = dtY.toString()+"-"+dtM.toString(10,2)+"-"+dtD.toString(10,2)+"T"+dtH+":"+data.charCodeAt(2+1).toString(10,2)+":"+data.charCodeAt(2+0).toString(10,2);
	}
	// Archive last month
	data = SYS.strFromCharCode(0x3, 0x1, 0x1C, 0, 3);
	if(arhLastM.isEVal() && !t_err.toInt() && !(t_err=req(data)).toInt()) {
		dtY = data.charCodeAt(2+5)+2000; dtM = data.charCodeAt(2+4); dtD = data.charCodeAt(2+3); dtH = data.charCodeAt(2+2);
		arhs[2].tmLast = SYS.mktime(0, 0, dtH, dtD, dtM-1, dtY);
		arhLastM = dtY.toString()+"-"+dtM.toString(10,2)+"-"+dtD.toString(10,2)+"T"+dtH+":"+data.charCodeAt(2+1).toString(10,2)+":"+data.charCodeAt(2+0).toString(10,2);
	}
	// Count hour
	data = SYS.strFromCharCode(0x3, 0x1, 0x1F, 0, 1);
	if(cntH.isEVal() && !t_err.toInt() && !(t_err=req(data)).toInt())
		cntH = data.charCodeAt(2);

	//Archives array processing
	arhSt = "";
	for(iA = 0; !arhStart_.isEVal() && iA < arhs.length; iA++) {
		aO = arhs[iA];
		if(aO.tmLast.isEVal())	continue;
		arhSt += (arhSt.length?"; ":"")+aO.id + ": ";
		SYS.messDebug("/GB","Archive "+aO.id+"; arh="+aO.arh);
		if(!aO.arh.length)	{ arhSt += tr("Disabled"); continue; }
		if(t_err.toInt())	arhSt += tr("Missed by error - ");

		//Initiate the archive reading current point
		if(!aO.tm)	aO.tm = max(arhStart_, aO.tmLast-aO.cnt*aO.per);
		
		//Requests
		while(!t_err.toInt() && aO.tm <= aO.tmLast && (SYS.time()-tmCur) < arhTmLim) {
			SYS.localtime(aO.tm, 0, 0, dtH, dtD, dtM, dtY);
			SYS.messDebug("/GB","Requesting "+aO.id+" for "+dtY+"-"+(dtM+1)+"-"+dtD+"T"+dtH+":0:0");
			data = SYS.strFromCharCode(aO.func, 0, 0, dtH, dtD, dtM+1, dtY-2000);
			if(!(t_err=req(data)).toInt() && data.length == 33) {
				archSet("vAccResult", aO.tm, aO.arh, data.charCodeAt(7,"UTF-32"));
				archSet("vAccWork", aO.tm, aO.arh, data.charCodeAt(11,"UTF-32"));
				archSet("vResult", aO.tm, aO.arh, 1e-4*data.charCodeAt(15,"UTF-32"));
				archSet("vWork", aO.tm, aO.arh, 1e-4*data.charCodeAt(19,"UTF-32"));
				archSet("p", aO.tm, aO.arh, 1e-1*data.charCodeAt(23,"UTF-16"));
				archSet("t", aO.tm, aO.arh, 1e-2*data.charCodeAt(25,"UTF-16"));
				archSet("notWorkTm", aO.tm, aO.arh, data.charCodeAt(27,"UTF-16"));
				aO.tm += aO.per;
			}
		}

		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.tm >= aO.tmLast) arhSt += tr("Trace for current time=%1").replace("%1",SYS.strftime(aO.tm,dtForm));
		else arhSt += tr("Initial reading in time=%1").replace("%1",SYS.strftime(aO.tm,dtForm));
		SYS.cntrReq(SYS.XMLNode("save").setAttr("path",this.nodePath()+"/%2fobj").setAttr("force",1));
	}

	tmPrev = tmCur;
}

if(!t_err.toInt() && aStStr.length)	t_err = "0:"+aStStr;
f_err = t_err+arhSt;