(загрузить pdf, 1Mb) : release
(загрузить pdf, 1Mb) : release
(загрузить pdf, 1Mb) : release
Свойства блока:
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;
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;
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';
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';
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;
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;
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;
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
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]);
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 can’t 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.
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;
END_FUNCTION_BLOCK
Интересные места:
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.
Неожиданно, немного магии в исходнике :):
m o d b u s
Проверка на идентичность:
m o d b u s