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","MBBase").setAttr("node",addr).setText(PDU);
	if((rez=tr.messIO(reqO,"ModBus")).length)	return "10:"+rez;
	PDU = reqO.text();

	return reqO.attr("err");
}

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

//Parse the items set and create user attributes
if(items != items_) {
	items_ = items;
	// Mark for check to deletion needs
	for(iSp = 0; iSp < 2; iSp++) {
		dtW = (iSp == 1) ? dtI : dt;
		for(var iDt in dtW)
			if(iDt != "10000") dtW[iDt].mark = false;
	}
	// Append/Update present ones
	for(off = 0; (sIt=items.parseLine(0,off)).length || off < items.length; ) {
		if(!sIt.length || 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);
		if(!itO.nm.length) itO.nm = itO.id;
		if(itO.md.indexOf("i") >= 0)
			dtI[itO.addr.toString(16,5)] = itO;
		else 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 { 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("/MB/"+this.cfg("SHIFR"),"itO="+itO.id+"; tmpAddr="+tmpAddr+"; addr="+itO.addr);
		}
	}
	dt["10000"] = EVAL; dtI["10000"] = EVAL;
	// Check, remove item and set to EVAL the attribute
	for(iSp = 0; iSp < 2; iSp++) {
		dtW = (iSp == 1) ? dtI : dt;
		for(var iDt in dtW) {
			if(iDt == "10000" || dtW[iDt].mark)	continue;
			this[dtW[iDt].id].set(EVAL, 0, 0, true);
			delete dtW[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;
			fragMerge = this.cntr().cfg("FRAG_MERGE");
			if(fragMerge.isEVal())	fragMerge = false;
		}
	} else tr = (tr_=SYS.Transport.outAt(transport)) ? tr_ : EVAL;
		    //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("/MB/"+this.cfg("SHIFR"),"reqPDU="+SYS.strDecode(PDU.string,"Bin"," "));
		if(!req(PDU.string).toInt())	itO.val = tVl;
		//SYS.messInfo("/MB/"+this.cfg("SHIFR"),"respPDU="+SYS.strDecode(PDU.string,"Bin"," "));
	}

	//Same requests for the data
	for(iSp = 0; iSp < 2; iSp++) {
		dtW = (iSp == 1) ? dtI : dt;

		blk = new Array();
		for(var iDt in dtW) {
			isEOL = (iDt == "10000");
			itO = dtW[iDt];
			//SYS.messInfo("/MB/"+this.cfg("SHIFR"),"iDt="+iDt+"; isEOL="+isEOL);
			if(!isEOL && (!blk.length || (
					(itO.addr-blk[0].addr+1+floor((itO.sz-2)/2)) <= floor(maxBlkSz/2) && (fragMerge || (itO.addr-blk[blk.length-1].addr-floor((blk[blk.length-1].sz-2)/2)) <= 1) ))) {
				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 + floor((blk[blk.length-1].sz-2)/2);
				PDU = SYS.strFromCharCode((iSp==1)?4:3, (blk[0].addr>>8)&0xFF, blk[0].addr&0xFF, 0, regN);
				//SYS.messInfo("/MB/"+this.cfg("SHIFR"), "reqPDU="+SYS.strDecode(PDU,"Bin"," "));
				if((tErr=req(PDU)).toInt()) break;
				//SYS.messInfo("/MB/"+this.cfg("SHIFR"), "respPDU="+SYS.strDecode(PDU,"Bin"," "));
				io = Special.FLibSYS.IO(PDU, "", "b");
				rF = io.read("uint8", 1); rN = io.read("uint8", 1);
				if(/*rF != 3 ||*/ (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)*2;
					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 {
						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);
			}
		}
	}
}

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