MODBUS: MODBUSCP

: 2014-10-16

: komatic

: SCL



, .



modbus



Siemens, Open MODBUS/TCP.
.





.



Siemens, Open MODBUS/TCP.



modbus


- ( pdf, 1Mb)





:



Name: FB108
Symbolic Name: MODBUSCP
Symbol Comment:
Family: COMM
Version: 2.2
Author: SIEMENS
Last modified: 06/08/2011
Use: FB106,FB107,SFC20,SFC51,SFC52,SFC6
Size in work memory: 6244 bytes
Object name: fb 108nc
Signature: generiert vom SCL Übersetzer Version: SCLCOMP K05.03.05.00_01.03.00.01 release



:



{
Scl_ResetOptions ;
Scl_OverwriteBlocks:= 'y' ;
Scl_GenerateReferenceData := 'y' ;
Scl_S7ServerActive:= 'y' ;
Scl_CreateObjectCode:= 'y' ;
Scl_OptimizeObjectCode:= 'y' ;
Scl_MonitorArrayLimits:= 'n' ;
Scl_CreateDebugInfo := 'n' ;
Scl_SetOKFlag:= 'n' ;
Scl_SetMaximumStringLength:= '254'
}
FUNCTION_BLOCK FB1108
TITLE ='MODBUSCP'
{ S7_tasklist := 'OB100' }
AUTHOR : SIEMENS
FAMILY : COMM
NAME : MODBUSCP
VERSION : '2.2'
// reversed by komatic
 
LABEL
_EXIT;
END_LABEL
 
 
 
VAR_INPUT
id : WORD ; //Connection-ID as per configuration in NetPro 1 to 64
laddr : WORD ; // Input-Address of the CP in HW Config
MONITOR : TIME ; //Monitoring Time: Wait for data from communication partner Shortest adjustable time is 20 ms
REG_KEY : STRING [17 ] := ' '; // Registration key to activate the license
REG_KEY_b AT REG_KEY :
STRUCT
length: BYTE;
act_length: BYTE;
str: ARRAY [0..15] OF BYTE;
END_STRUCT;
server_client : BOOL ; // CP/FB operates in server mode or client mode
single_write : BOOL ; // Write 1 Coil/Register: Function code 5 and 6 are used respectively Function code 15 and 16 are used respectively
data_type_1 : BYTE ; // 1st data area: data type Coils Inputs Holding Register Input Register 0 to 4
db_1 : WORD ; // 1st data area: data block number 1 to 65535
start_1 : WORD ; // 1st data area: first Modbus address in this DB 0 to 65535
end_1 : WORD ; // 1st data area: last Modbus address in this DB 0 to 65535
data_type_2 : BYTE ; // 2nd data area: data type (Coils, Inputs, Holding Register, Input Register), NULL if not used
db_2 : WORD ; // 2nd data area: data block number
start_2 : WORD ; // 2nd data area: first Modbus address in this DB
end_2 : WORD ; // 2nd data area: last Modbus address in this DB
data_type_3 : BYTE ; // ...
db_3 : WORD ;
start_3 : WORD ;
end_3 : WORD ;
data_type_4 : BYTE ;
db_4 : WORD ;
start_4 : WORD ;
end_4 : WORD ;
data_type_5 : BYTE ;
db_5 : WORD ;
start_5 : WORD ;
end_5 : WORD ;
data_type_6 : BYTE ;
db_6 : WORD ;
start_6 : WORD ;
end_6 : WORD ;
data_type_7 : BYTE ;
db_7 : WORD ;
start_7 : WORD ;
end_7 : WORD ;
data_type_8 : BYTE ;
db_8 : WORD ;
start_8 : WORD ;
end_8 : WORD ;
ENQ_ENR : BOOL ; // CP is client: Initiate request at TRUE signal CP is server: Ready to receive at TRUE signal
END_VAR
VAR_OUTPUT
LICENSED : BOOL ; // License state of the function block: Block is licensed Block is not licensed
BUSY : BOOL ; // Operating state of the functions AG_SEND and AG_RECV Job processing No job processing active
DONE_NDR : BOOL ; // CP is client: Active request finished without errors CP is server: Request from the client was executed and answered
ERROR : BOOL ; // An error has occurred No error has occurred
STATUS : WORD ; // Error number
STATUS_FUNC : STRING [8 ]; // Name of the function, which causes the error at STATUS
STATUS_FUNC_b AT STATUS_FUNC : ARRAY [0..1] OF BYTE ;
IDENT_CODE : STRING [18 ]; // Identification for licensing Please order your license with this identification string.
END_VAR
VAR_IN_OUT
UNIT : BYTE ; // Unit identification (INPUT if in CLIENT mode, OUTPUT if in SERVER mode) 0 to 255
DATA_TYPE : BYTE ; // Data type to be accessed: (INPUT if in CLIENT mode, OUTPUT if in SERVER mode) Coils Inputs Holding registers Input registers
START_ADDRESS : WORD ; // MODBUS start address (INPUT if in CLIENT mode, OUTPUT if in SERVER mode)
LENGTH : WORD ; // Number of registers to be processed (INPUT if in CLIENT mode, OUTPUT if in SERVER mode) Coils: reading function
WRITE_READ : BOOL ; // INPUT if in CLIENT mode, OUTPUT if in SERVER mode: Write access Read access
END_VAR
VAR
TI : WORD ; // Transaction Identifier (INPUT if in CLIENT mode, OUTPUT if in SERVER mode)
SEND_BUFFER : ARRAY [1 .. 260 ] OF BYTE ;
RECV_BUFFER1 : ARRAY [1 .. 6 ] OF BYTE ;
RECV_BUFFER2 : ARRAY [1 .. 260 ] OF BYTE ;
MB_CPCLI : FB106;
MB_CPSRV : FB107;
TON : SFB4;
sIDB_Nr : WORD ;
sLADDR : WORD ;
sID : WORD ;
sSTATUS_TEMP : WORD ;
sSTATUS_TIMER : WORD ;
sSTATUS_FUNC : STRING [8 ];
sSTATUS_CODE : STRING [17 ];
sSTATUS_CODE_b AT sSTATUS_CODE :
STRUCT
length: BYTE;
act_length: BYTE;
str: ARRAY [0..15] OF BYTE;
END_STRUCT;
sDATA_AREAS : DINT ;
sSEND_BUFFER : DINT ;
sRECV1_BUFFER : DINT ;
sRECV2_BUFFER : DINT ;
sSERVER_CLIENT : BOOL ;
sSINGLE_WRITE : BOOL ;
sANLAUF_FEHLER : BOOL ;
sANLAUF : BOOL ;
sAREA_VALID : ARRAY [1 .. 8 ] OF BOOL ;
sAREA_1 : ARRAY [1 .. 2 ] OF CHAR := 'M', 'O';
sAREA_2 : ARRAY [1 .. 4 ] OF CHAR := 'D', 'B', 'U', 'S';
sStart_x : DINT ;
sEnd_x : DINT ;
sStart_y : DINT ;
sEnd_y : DINT ;
tDbNr : WORD ;
i : INT ;
j : INT ;
pos : INT ;
k : INT ;
reg : INT ;
sDataType : WORD ;
snd_time : BYTE ;
rcv_time : BYTE ;
sACODE : ARRAY [0 .. 17 ] OF BYTE ;
H_STATION : BYTE ;
H_STATION_TIME : TIME ;
RD_SINFO : STRUCT
RET_WERT : INT ;
TOP_SI : STRUCT
EV_CLASS : BYTE ;
EV_NUM : BYTE ;
PRIORITY : BYTE ;
NUM : BYTE ;
TYP2_3 : BYTE ;
TYP1 : BYTE ;
ZI1 : WORD ;
ZI2_3 : DWORD ;
END_STRUCT ;
START_UP_SI : STRUCT
EV_CLASS : BYTE ;
EV_NUM : BYTE ;
PRIORITY : BYTE ;
NUM : BYTE ;
TYP2_3 : BYTE ;
TYP1 : BYTE ;
ZI1 : WORD ;
ZI2_3 : DWORD ;
END_STRUCT ;
END_STRUCT ;
RDSYSST : STRUCT
RET_WERT : INT ;
REQ : BOOL ;
BUSY : BOOL ;
SZL_HEADER : STRUCT
LENTHDR : WORD ;
N_DR : WORD ;
END_STRUCT ;
SZL_11C_5 : STRUCT
index : WORD ;
serialn : ARRAY [0 .. 23 ] OF CHAR ;
res : ARRAY [1 .. 4 ] OF WORD ;
END_STRUCT ;
END_STRUCT ;
CPU_DATA : STRUCT
Index : WORD ;
CPUIdent : ARRAY [1 .. 20 ] OF BYTE ;
Reserved : WORD ;
MajorVersion : WORD ;
MinorVersion_1 : BYTE ;
MinorVersion_2 : BYTE ;
END_STRUCT ;
sdata_type_1 : BYTE ;
sdb_1 : WORD ;
sstart_1 : WORD ;
send_1 : WORD ;
sdata_type_2 : BYTE ;
sdb_2 : WORD ;
sstart_2 : WORD ;
send_2 : WORD ;
sdata_type_3 : BYTE ;
sdb_3 : WORD ;
sstart_3 : WORD ;
send_3 : WORD ;
sdata_type_4 : BYTE ;
sdb_4 : WORD ;
sstart_4 : WORD ;
send_4 : WORD ;
sdata_type_5 : BYTE ;
sdb_5 : WORD ;
sstart_5 : WORD ;
send_5 : WORD ;
sdata_type_6 : BYTE ;
sdb_6 : WORD ;
sstart_6 : WORD ;
send_6 : WORD ;
sdata_type_7 : BYTE ;
sdb_7 : WORD ;
sstart_7 : WORD ;
send_7 : WORD ;
sdata_type_8 : BYTE ;
sdb_8 : WORD ;
sstart_8 : WORD ;
send_8 : WORD ;
sHoldingRegisterState : ARRAY [0 .. 24 ] OF BYTE ;
END_VAR
VAR_TEMP
tSProductID : STRING [19 ];
tSProductID_b AT tSProductID : STRUCT
length : BYTE;
act_length : BYTE;
str : ARRAY [0..17] OF BYTE;
END_STRUCT;
 
tALicenseKey : ARRAY [0 .. 17 ] OF BYTE ;
IDB_Struct : STRUCT
ANY_id : WORD ;
Length : WORD ;
DB_Number : WORD ;
Byte_Pointer : DWORD ;
END_STRUCT ;
IDB_Struct_any AT IDB_Struct : ANY ;
END_VAR
 
BEGIN
 
RD_SINFO.RET_WERT := RD_SINFO(TOP_SI:=RD_SINFO.TOP_SI, START_UP_SI:=RD_SINFO.START_UP_SI);
 
IF RD_SINFO.RET_WERT <> 0
THEN
ERROR:=true;
STATUS:=INT_TO_WORD(RD_SINFO.RET_WERT);
sSTATUS_FUNC:='RD_SINFO';
ELSE // call in cyclic OB (normal work)
IF RD_SINFO.TOP_SI.NUM=1 OR (BYTE_TO_INT(RD_SINFO.TOP_SI.NUM) >= 30 AND BYTE_TO_INT(RD_SINFO.TOP_SI.NUM) <= 38)
THEN
BUSY:=false;
DONE_NDR:=false;
ERROR:=false;
STATUS:=W#16#0;
STATUS_FUNC:=' ';
STATUS_FUNC_b[1]:=B#16#0;
IF sSERVER_CLIENT
THEN
UNIT:=0;
DATA_TYPE:=0;
START_ADDRESS:=0;
LENGTH:=0;
WRITE_READ:=false;
END_IF;

IDB_Struct_any:=sIDB_Nr;
 
IF sIDB_Nr <> IDB_Struct.DB_Number OR sANLAUF_FEHLER
THEN
ERROR:=true;
IF sANLAUF_FEHLER
THEN
STATUS_FUNC:=sSTATUS_FUNC;
STATUS:=sSTATUS_TEMP;
ELSE
STATUS:=W#16#A080; // Different instance DBs were used for the call of MODBUSCP in OB100 and the cyclic OB.
STATUS_FUNC:='MODBUSCP';
END_IF;
ELSE
IF NOT ERROR
THEN
IF NOT sSERVER_CLIENT
THEN
IF ENQ_ENR
THEN
TI:=DINT_TO_WORD(WORD_TO_DINT(TI)+1);
END_IF;
// call client
MB_CPCLI(
ID := WORD_TO_INT(sID)
,LADDR := sLADDR
,IDB_NR := WORD_TO_BLOCK_DB(sIDB_Nr)
,MONITOR := MONITOR
,ENQ_ENR := ENQ_ENR
,SERVER_CLIENT := sSERVER_CLIENT
,ANLAUF := sANLAUF
,SINGLE_WRITE := sSINGLE_WRITE
,DATA_AREAS := sDATA_AREAS
,SEND_BUFFER := sSEND_BUFFER
,RECV1_BUFFER := sRECV1_BUFFER
,RECV2_BUFFER := sRECV2_BUFFER
,AREA_VALID := sAREA_VALID
,UNIT := UNIT
,DATA_TYPE := DATA_TYPE
,START_ADDRESS := START_ADDRESS
,LENGTH := LENGTH
,TI := TI
,WRITE_READ := WRITE_READ
);

DONE_NDR := MB_CPCLI.DONE_NDR;
BUSY := MB_CPCLI.BUSY;
ERROR := MB_CPCLI.ERROR;
STATUS := MB_CPCLI.STATUS;
STATUS_FUNC := MB_CPCLI.STATUS_FUNC;
 
ELSE
// call server
MB_CPSRV(
ID := WORD_TO_INT(sID)
,LADDR := sLADDR
,IDB_NR := WORD_TO_BLOCK_DB(sIDB_Nr)
,MONITOR := MONITOR
,ENQ_ENR := ENQ_ENR
,DATA_AREAS := sDATA_AREAS
,SERVER_CLIENT := sSERVER_CLIENT
,ANLAUF := sANLAUF
,SEND_BUFFER := sSEND_BUFFER
,RECV1_BUFFER := sRECV1_BUFFER
,RECV2_BUFFER := sRECV2_BUFFER
);
UNIT := MB_CPSRV.UNIT;
DATA_TYPE := MB_CPSRV.DATA_TYPE;
START_ADDRESS := MB_CPSRV.START_ADDRESS;
LENGTH := MB_CPSRV.LENGTH;
TI := MB_CPSRV.TI;
WRITE_READ := MB_CPSRV.WRITE_READ;
DONE_NDR := MB_CPSRV.DONE_NDR;
BUSY := MB_CPSRV.BUSY;
ERROR := MB_CPSRV.ERROR;
STATUS := MB_CPSRV.STATUS;
STATUS_FUNC := MB_CPSRV.STATUS_FUNC;
END_IF;
sANLAUF:=false;
END_IF;
END_IF;
 
IF H_STATION = B#16#0
THEN // check if H-CPU
RDSYSST.RET_WERT:=RDSYSST( // Module identification
REQ := true
,SZL_ID := W#16#111 // W#16#0111: a single identification data record
,INDEX := W#16#1 // W#16#0001: identification of the module
,BUSY := RDSYSST.BUSY
,SZL_HEADER := RDSYSST.SZL_HEADER
,DR := CPU_DATA // Order number of the module; String consists of 19 characters and a blank (20H); such as for CPU 314: "6ES7 314-0AE01-0AB0"
);
IF NOT RDSYSST.BUSY
THEN
IF RDSYSST.RET_WERT = 0
THEN
IF BYTE_TO_INT(CPU_DATA.CPUIdent[11]) = 72 // 'H' if H-CPU
THEN
H_STATION:= B#16#1;
H_STATION_TIME:=T#1M;
ELSE
H_STATION:=B#16#2;
H_STATION_TIME:=T#4S;
END_IF;
ELSE
ERROR:=true;
STATUS:=INT_TO_WORD(RDSYSST.RET_WERT);
STATUS_FUNC:='RDSYSST';
END_IF;
END_IF;
ELSE
j:=0;
REG_KEY_b.act_length:=B#16#11;
tSProductID:='MODCP2XV94501MB00';

IF (sSTATUS_TIMER AND W#16#60) <> W#16#0
THEN
IF (sSTATUS_TIMER AND W#16#20) <> W#16#0
THEN
RDSYSST.REQ:=true;
sSTATUS_TIMER:=sSTATUS_TIMER OR W#16#4000;
ELSE
RDSYSST.REQ:=false;
END_IF;


RDSYSST.RET_WERT:=RDSYSST(
REQ := RDSYSST.REQ
,SZL_ID := W#16#11C // SSL-ID W#16#xy1C - Component Identification
,INDEX := W#16#5 // W#16#0005: Serial number of the module
,BUSY := RDSYSST.BUSY
,SZL_HEADER := RDSYSST.SZL_HEADER
,DR := RDSYSST.SZL_11C_5
);
// Serial number OF the module; character STRING with MAX. length OF 24
// characters. Shorter numbers are filled with B#16#00.
// Note: This serial number is unique world-wide FOR SIMATIC components AND
// permanently associated TO the CPU hardware, that is, it remains unchanged
// when a firmware update is performed.

IF RDSYSST.RET_WERT<>0 AND
RDSYSST.RET_WERT<>129 AND // W#16#0081 Result field too short. (Nevertheless as many data records as possible are supplied. The SSL header indicates this number.)
RDSYSST.RET_WERT<>-32638 AND // W#16#8082 SSL_ID is wrong or is unknown in the CPU or SFC.
RDSYSST.RET_WERT<>-32637 // W#16#8083 INDEX wrong or not permitted.
THEN
IF RDSYSST.RET_WERT=-32635 // W#16#8085 Due to a problem in the system, information is not currently available (for example, due to a lack of resources).
THEN
tSProductID:='CPU0 not reachable';

j:=BLKMOV(SRCBLK := tSProductID, DSTBLK := IDENT_CODE);
END_IF;

ERROR:=true;
STATUS:=INT_TO_WORD(RDSYSST.RET_WERT);
STATUS_FUNC:='RDSYSST';
ELSE
IF RDSYSST.BUSY
THEN
sSTATUS_TIMER:=(sSTATUS_TIMER AND W#16#FFBF) OR W#16#40;
ELSE
sSTATUS_TIMER:=sSTATUS_TIMER AND W#16#FF9F;

FOR i:= 0 TO 16 BY 1 DO
// result - string with symbols in range 'A'-'M'
sACODE[INT_TO_DINT(i)]:=INT_TO_BYTE(BYTE_TO_INT(CHAR_TO_BYTE(RDSYSST.SZL_11C_5.serialn[INT_TO_DINT(i)]) XOR (tSProductID_b.str[INT_TO_DINT(i)])) MOD 13 + 65);
END_FOR;

sACODE[17]:=B#16#32; // '2'
j:=BLKMOV( SRCBLK := sACODE, DSTBLK := IDENT_CODE);

END_IF;
END_IF;
END_IF;

IF sACODE[17]=B#16#32 // '2'
THEN
reg:=0;
 
WHILE reg<=16 DO
IF REG_KEY_b.str[reg] <> sSTATUS_CODE_b.str[reg]
THEN
j:=BLKMOV(SRCBLK := IDENT_CODE, DSTBLK := sACODE );

IF j=0
THEN
FOR i:=0 TO 16 BY 1 DO
rcv_time:= SHL(IN:=B#16#1, N:=BYTE_TO_INT(INT_TO_BYTE(i) AND 7));

FOR k:=0 TO 7 BY 1 DO
snd_time:= SHL(IN:=B#16#1, N:=7-k);
pos:=i/8*8+k;

IF (tSProductID_b.str[i] AND snd_time) = snd_time
THEN
sHoldingRegisterState[pos]:=sHoldingRegisterState[pos] OR rcv_time ;

END_IF;
END_FOR;
END_FOR;

FOR i:=0 TO 16 BY 1 DO
tALicenseKey[i]:=(sACODE[i] XOR sHoldingRegisterState[i]) XOR INT_TO_BYTE(i+1);
tALicenseKey[i]:=INT_TO_BYTE(BYTE_TO_INT(tALicenseKey[i]) MOD 26 + 65); // 65='A'
END_FOR;

tALicenseKey[17]:=B#16#0;

FOR i:=0 TO 23 BY 1 DO
sHoldingRegisterState[i]:=B#16#0;
END_FOR;

j:=BLKMOV(SRCBLK :=REG_KEY,DSTBLK :=sACODE);

IF j=0
THEN
FOR i:=0 TO 16 BY 1 DO
IF tALicenseKey[i]<>sACODE[i]
THEN
sSTATUS_TIMER:=sSTATUS_TIMER AND W#16#FFFB;
LICENSED:=false;
EXIT;
END_IF;
IF i=16
THEN
sSTATUS_TIMER:=sSTATUS_TIMER OR W#16#4;
LICENSED:=true;
END_IF;
END_FOR;
END_IF;
END_IF;

j:=BLKMOV(SRCBLK := REG_KEY,DSTBLK := sSTATUS_CODE);
END_IF;
reg:=reg+1;
END_WHILE;
END_IF;

IF ((sSTATUS_TIMER AND W#16#4) = W#16#0) AND NOT sANLAUF_FEHLER
THEN

TON(IN := TON.IN ,PT := H_STATION_TIME);
TON.IN:=true;
 
IF TON.Q
THEN
TON.IN:=DB0.DBX0.0; //???????
TON.IN:=false;

sSTATUS_TEMP:=INT_TO_WORD(WR_USMSG(SEND := false
,EVENTN := W#16#A090 // The block MODBUSCP is not licensed for this CPU. This is a status information. The bit ERROR is not set. The Modbus communication runs without a license as well.
,INFO1 := sAREA_1
,INFO2 := sAREA_2
));
 
IF sSTATUS_TEMP<>W#16#0
THEN
ERROR:=true;
STATUS:=sSTATUS_TEMP;
STATUS_FUNC:='WR_USMSG';
END_IF;
END_IF;
IF STATUS = W#16#0 THEN STATUS:=W#16#A090; END_IF; // The block MODBUSCP is not licensed for this CPU. This is a status information. The bit ERROR is not set. The Modbus communication runs without a license as well.
END_IF;
IF j<>0
THEN
ERROR:=true;
STATUS:=W#16#A085;// An error occurred during the license handling due to an invalid write access.
STATUS_FUNC:='MODBUSCP';
END_IF;
END_IF;
ELSE

// this part work in start OB100..OB102 (initialization)
IF BYTE_TO_INT(RD_SINFO.TOP_SI.NUM)>=100 AND BYTE_TO_INT(RD_SINFO.TOP_SI.NUM)<=102
THEN
BUSY:=false;
DONE_NDR:=false;
ERROR:=false;
STATUS:=W#16#0;
STATUS_FUNC:=' ';
STATUS_FUNC_b[1]:=B#16#0;
IF sSERVER_CLIENT
THEN
UNIT:=0;
DATA_TYPE:=0;
START_ADDRESS:=0;
LENGTH:=0;
WRITE_READ:=false;
END_IF;
sANLAUF_FEHLER:=false;
sSTATUS_TEMP:=W#16#0;
sSTATUS_FUNC:='';
sSTATUS_CODE:='';
 
FOR i:=1 TO 8 BY 1 DO sAREA_VALID[i]:=false; END_FOR;

IF WORD_TO_INT(id)<=0 OR WORD_TO_INT(id)>64 // An invalid value id is parameterized. Range of values is 1 to 64.
THEN
STATUS:=W#16#A07A;
ELSE

sID:=id;
sLADDR:=laddr;
sSERVER_CLIENT:=server_client;
sSINGLE_WRITE:=single_write;

IDB_Struct_any:=sIDB_Nr;
sIDB_Nr:=IDB_Struct.DB_Number;
IDB_Struct_any:=sdata_type_1;
sDATA_AREAS:=DWORD_TO_DINT(SHR(IN:=DW#16#FFFFFF AND IDB_Struct.Byte_Pointer, N:=3));

IDB_Struct_any:=SEND_BUFFER[1];
sSEND_BUFFER:=DWORD_TO_DINT(SHR(IN:=DW#16#FFFFFF AND IDB_Struct.Byte_Pointer, N:=3));

IDB_Struct_any:=RECV_BUFFER1[1];
sRECV1_BUFFER:=DWORD_TO_DINT(SHR(IN:=DW#16#FFFFFF AND IDB_Struct.Byte_Pointer, N:=3));

IDB_Struct_any:=RECV_BUFFER2[1];
sRECV2_BUFFER:=DWORD_TO_DINT(SHR(IN:=DW#16#FFFFFF AND IDB_Struct.Byte_Pointer, N:=3));
 
sdata_type_1 :=data_type_1;
sdb_1 :=db_1;
sstart_1 :=start_1;
send_1 :=end_1;
sdata_type_2 :=data_type_2;
sdb_2 :=db_2;
sstart_2 :=start_2;
send_2 :=end_2;
sdata_type_3 :=data_type_3;
sdb_3 :=db_3;
sstart_3 :=start_3;
send_3 :=end_3;
sdata_type_4 :=data_type_4;
sdb_4 :=db_4;
sstart_4 :=start_4;
send_4 :=end_4;
sdata_type_5 :=data_type_5;
sdb_5 :=db_5;
sstart_5 :=start_5;
send_5 :=end_5;
sdata_type_6 :=data_type_6;
sdb_6 :=db_6;
sstart_6 :=start_6;
send_6 :=end_6;
sdata_type_7 :=data_type_7;
sdb_7 :=db_7;
sstart_7 :=start_7;
send_7 :=end_7;
sdata_type_8 :=data_type_8;
sdb_8 :=db_8;
sstart_8 :=start_8;
send_8 :=end_8;
 
FOR i:= 1 TO 8 BY 1 DO
sDataType:=BYTE_TO_WORD(WORD_TO_BLOCK_DB(sIDB_Nr).DB[(i-1)*8+sDATA_AREAS]);

IF WORD_TO_INT(sDataType)<0 OR WORD_TO_INT(sDataType)>4 THEN STATUS:=W#16#A07C; EXIT; END_IF; // An invalid value data_type_x was given. The value range is 0 to 4.
IF sDataType<>W#16#0
THEN
sAREA_VALID[i]:=true;
ELSE
IF i=1 THEN STATUS:=W#16#A07D; EXIT; END_IF; // Parameter data_type_1 is not defined. The parameter area _1 is the default area and must be defined.
END_IF;
END_FOR;
 
FOR i:= 1 TO 8 BY 1 DO
IF sAREA_VALID[i]
THEN
sDataType:= BYTE_TO_WORD(WORD_TO_BLOCK_DB(sIDB_Nr).DB[(i-1)*8+sDATA_AREAS]);
sStart_x:= WORD_TO_DINT(WORD_TO_BLOCK_DB(sIDB_Nr).DW[sDATA_AREAS+4+(i-1)*8]);
sEnd_x:= WORD_TO_DINT(WORD_TO_BLOCK_DB(sIDB_Nr).DW[sDATA_AREAS+6+(i-1)*8]);
IF sStart_x>sEnd_x THEN STATUS:=W#16#A002; EXIT; END_IF; // The parameter end_x is less than start_x.
tDbNr:= WORD_TO_BLOCK_DB(sIDB_Nr).DW[sDATA_AREAS+2+(i-1)*8];
IF tDbNr=W#16#0 THEN STATUS:=W#16#A019; EXIT; END_IF; // 0 is assigned to one of the parameters db_x while the according data_type_x is <> 0. DB 0 cant be used; it is reserved for system functions.
IF tDbNr=sIDB_Nr THEN STATUS:=W#16#A07E; EXIT; END_IF; // The DB number of db_x is identical to the number of the instance DB.
 
FOR j:= i+1 TO 8 BY 1 DO
IF sAREA_VALID[j]
THEN

IF tDbNr=WORD_TO_BLOCK_DB(sIDB_Nr).DW[sDATA_AREAS+2+(j-1)*8] THEN STATUS:=W#16#A010; EXIT; END_IF; // In the parameterized area db_1 to db_8 a DB number is used twice.
sStart_y:=WORD_TO_DINT(WORD_TO_BLOCK_DB(sIDB_Nr).DW[sDATA_AREAS+4+(j-1)*8]);
sEnd_y :=WORD_TO_DINT(WORD_TO_BLOCK_DB(sIDB_Nr).DW[sDATA_AREAS+6+(j-1)*8]);

IF BYTE_TO_WORD(WORD_TO_BLOCK_DB(sIDB_Nr).DB[(j-1)*8+sDATA_AREAS])=sDataType
THEN
IF (sStart_y>=sStart_x AND sStart_y<=sEnd_x) OR (sEnd_y>=sStart_x AND sEnd_y<=sEnd_x)
THEN
STATUS:=SHL(IN:=INT_TO_WORD(i),N:=4) OR W#16#A000 OR INT_TO_WORD(j); // The parameterized areas overlap.
EXIT;
END_IF;
END_IF;
END_IF;
END_FOR;

IF STATUS<>W#16#0 THEN EXIT; END_IF;
END_IF;
END_FOR;
END_IF;
IF STATUS <> W#16#0
THEN
ERROR:=true;
sANLAUF_FEHLER:=true;
sSTATUS_TEMP:=STATUS;
sSTATUS_FUNC:='MODBUSCP';
STATUS_FUNC:=sSTATUS_FUNC;
END_IF;
H_STATION:=B#16#0;
sSTATUS_TIMER:=sSTATUS_TIMER OR W#16#20;
sANLAUF:=true;
END_IF;
END_IF;
END_IF;
 
END_FUNCTION_BLOCK
 



:





H-CPU



IF H_STATION = B#16#0
THEN // check if H-CPU
RDSYSST.RET_WERT:=RDSYSST( // Module identification
REQ := true
,SZL_ID := W#16#111 // W#16#0111: a single identification data record
,INDEX := W#16#1 // W#16#0001: identification of the module
,BUSY := RDSYSST.BUSY
,SZL_HEADER := RDSYSST.SZL_HEADER
,DR := CPU_DATA // Order number of the module; String consists of 19 characters and a blank (20H); such as for CPU 314: "6ES7 314-0AE01-0AB0"
);
IF NOT RDSYSST.BUSY
THEN
IF RDSYSST.RET_WERT = 0
THEN
IF BYTE_TO_INT(CPU_DATA.CPUIdent[11]) = 72 // 'H' if H-CPU
THEN
H_STATION:= B#16#1;
H_STATION_TIME:=T#1M;






RDSYSST.RET_WERT:=RDSYSST(
REQ := RDSYSST.REQ
,SZL_ID := W#16#11C // SSL-ID W#16#xy1C - Component Identification
,INDEX := W#16#5 // W#16#0005: Serial number of the module
,BUSY := RDSYSST.BUSY
,SZL_HEADER := RDSYSST.SZL_HEADER
,DR := RDSYSST.SZL_11C_5
);
// Serial number OF the module; character STRING with MAX. length OF 24
// characters. Shorter numbers are filled with B#16#00.

, :):



modbus

? ...
- ?
Upd: , :).



:





modbus

Block checksum .





, (zip, 3Mb)







: 15506

: Control    : 2017-02-04

After compile, i don't have same block checksum as yours and siemens 0x0DCA.

: Majk    : 2017-09-05

!

:

(4000 max):

: