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

	// For other logical level
	reqO = SYS.XMLNode(mbType).setAttr("id","FlowGAS").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.messInfo("/FlowGAS/archSet","attr="+attr+"; vTm="+SYS.strftime(vTm)+"; arh="+arh+"; vl="+vl);
	atrO = this[attr];
	if(!atrO || atrO.isEVal()) return;
	arguments[attr] = vl;	//Setting the current value
	//if(vTm > atrO.time())	atrO.set(vl,vTm,0,true);
	if(atrO.arch())	atrO.arch().setVal(vTm*1e6, vl, arh);
}

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

if((f_start && typeof(arhs) != "array") || reset) {
	reset = false;
	//Archives init
	arhs = new Array();
	a = new Object();
	a.id = "Hours"; a.func = 1; a.dtSz = 28; a.pos = 14400; a.per = 3600;
	a.arh = arhH; a.attrs = new Array("p", "t", "vWork-d", "vResult-d");
	arhs.push(a);
	//...
}
if(f_start || f_stop) return;

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

if(f_start || f_stop) return;

tErr = "";

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

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

	//Archives array processing
	tmCur = SYS.time();
	arhSt = "";
	for(iA = 0; iA < arhs.length; iA++) {
		aO = arhs[iA];
		//if(aO.tmLast.isEVal())	continue;
		arhSt += (arhSt.length?"; ":"")+aO.id + ": ";
		SYS.messDebug("/FlowGAS","Archive "+aO.id+"; arh="+aO.arh);
		if(!aO.arh.length)	{ arhSt += tr("Disabled"); continue; }
		if(tErr.toInt())		arhSt += tr("Missed by an error - ");
		else {
			// The archive selection
			PDU = SYS.strFromCharCode(0x10, 0x01, 0x2f, 0, 1, 2, 0, aO.func);
			if((tErr=req(PDU)).toInt())	arhSt += tr("Missed by an error - ");
		}
		while(!tErr.toInt() && (SYS.time()-tmCur) < arhTmLim) {
			SYS.messDebug("/FlowGAS","Requesting "+aO.id+" for "+aO.pos);
			// The need position selection
			PDU = SYS.strFromCharCode(0x10, 0x01, 0x31, 0, 1, 2, aO.pos>>8, aO.pos&0xFF);
			if((tErr=req(PDU)).toInt())	{ arhSt += tr("Missed by an error - "); continue; }
			// The selected data reading
			PDU = SYS.strFromCharCode(4, 0x01, 0x41, 0, aO.dtSz/2);
			if((tErr=req(PDU)).toInt()) { arhSt += tr("Missed by an error - "); continue; }

			io = Special.FLibSYS.IO(PDU, "", "b"); io.pos = 2;
			dtD = io.read("uint8",1), dtM = io.read("uint8",1), dtY = io.read("uint8",1), dtH = io.read("uint8",1);
			aO.tm = SYS.mktime(0, 0, dtH, dtD, dtM-1, 2000+dtY);
			for(iA = 0; iA < aO.attrs.length; iA++)
				archSet(aO.attrs[iA].parse(0,"-"), aO.tm, aO.arh, (aO.attrs[iA].parse(1,"-")=="d") ? io.read("double",1,"b") : io.read("float",1,"b"));
			aO.pos = max(1, aO.pos-1);
		}

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

	// Requesting the data
	/*if(!tErr.toInt()) {
		PDU = SYS.strFromCharCode(0x10, 0x01, 0x2f, 0, 1, 2, 0, 1);
		//SYS.messInfo("/ED","reqPDU="+SYS.strDecode(PDU,"Bin"," "));
		if(!(tErr=req(PDU)).toInt()) {
			stTm = SYS.time();
			for( ; iRec > 0 && (SYS.time()-stTm) < 20; iRec--) {
				PDU = SYS.strFromCharCode(0x10, 0x01, 0x31, 0, 1, 2, iRec>>8, iRec&0xFF);
				if(!(tErr=req(PDU)).toInt()) {
					PDU = SYS.strFromCharCode(4, 0x01, 0x41, 0, 28/2);
					if(!(tErr=req(PDU)).toInt()) {
						io = Special.FLibSYS.IO(PDU, "", "b"); io.pos = 2;
						SYS.messInfo("/FlowGAS",
							"iRec="+iRec+"; "
							"DateTm="+io.read("uint8",1)+"."+io.read("uint8",1)+"."+io.read("uint8",1)+"T"+io.read("uint8",1)+"; "
							"P="+io.read("float",1,"b")+"; "
							"T="+io.read("float",1,"b")+"; "
							"AccWorkF="+io.read("double",1,"b")+"; "
							"AccStdF="+io.read("double",1,"b"));
//	01 04 1C
//10 02 16 17	- 16.02.22 23
//43 4B 10 5C - P
//40 7F 2F F5 - T
//41 0A 5D 88 00 00 00 00 - Overal accumulated work flow
//41 2C 5E 69 8E 6C 20 A1 - Overal accumulated standard flow
//45 01
					}
				}
			}
		}
	}*/
}

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