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