TCP/IP Com between Siemens and B&R

tevious

Member
Join Date
Feb 2015
Location
Balingen
Posts
22
Hello,

I try to do the communication between a Siemens PLC and a B&R PLC through TCP/IP connection. I've no experience in this field, and I'm completely stuck with a problem.

The Siemens is used to manage a circulation system and the B&R to control a plotting module, that's why Siemens is the server and B&R the client. The Siemens must give a array of characters to the B&R which informs this one about a filename that it has to search on another server, so we just want to transfer a array of char from the Siemens to the B&R...

Below is the source code in SCL for S7:

I checked the IP and ports for the both PLC and they match, I used the code from an example I found in Internet for S7, and for B&R it was directed in the IDE from the manufaturer.

For S7 I've the status for TCON with this number:80B3
which means it could be error from 80A0-80A2, 80A4, 80B4-80B9 which doesn't help...

S7 function block code (used in OB1-main, no problem with that)
with its source code will be put at the next post.

**************************************
For B&R, I used that code, the program runs between step 0-5-10-40 and loops again, if I change the port number in the step 10 at the line: Client.TcpClient_0.portserv := 12000;
it loops between 0-100 which means the communication with this port should work.

The code for B&R will be display at the over next post... (so long for only one)

Thanks for your help :geek:
 
Code for Step 7:

FUNCTION_BLOCK FB100
TITLE ='HTTP_REQUEST'
AUTHOR : 'Matze001'
VERSION : '0.1'

// ==========================================================================
// = Versionshistorie =
// = =
// = V0.1 22.11.2015 Matze001 =
// = ----------------------- =
// = Baustein erstellt, ungetestet =
// = URL http://www.sps-forum.de/simatic/69005-tcp-erbindung-mit-scl.html?highlight=tcp+beispiel+s7-300 =

// ==========================================================================

// ==========================================================================
// = Bausteinbeschreibung =
// = =
// ==========================================================================

VAR_TEMP


END_VAR
VAR


T_SEND: TSEND;
T_RCV: TRCV;
T_CONN: TCON;
T_PARAM: TCON_PAR;

CONNECT: BOOL;
CONNECTED: BOOL;
SENDEN: BOOL;
TIMEOUT_SEND: TON;

SEND: ARRAY[0..511] OF CHAR;
RECV: ARRAY[0..511] OF CHAR;

CONNEC_STATUS: INT;
RCV_STATUS: INT;
SEND_STATUS: INT;

END_VAR

VAR_INPUT
INIT: BOOL;
CONNECTION_ID: WORD;
IP_ADDR1: INT;
IP_ADDR2: INT;
IP_ADDR3: INT;
IP_ADDR4: INT;
END_VAR


VAR_OUTPUT

END_VAR

VAR_IN_OUT

END_VAR;

// Init Sequenz
// ####################################################################################################
IF Init THEN
CONNECT := FALSE;
CONNECTED:= FALSE;
SENDEN:= FALSE;
END_IF;

// Kommunikation
// ####################################################################################################
// ####################################################################################################

// Wenn noch keine Verbindung besteht Verbindung herstellen
// ####################################################################################################
IF NOT CONNECTED THEN

// Verbindungseinstellungen schreiben
T_PARAM.id:= CONNECTION_ID;
T_PARAM.CONNECTION_TYPE:= 17; // TCP
T_PARAM.LOCAL_DEVICE_ID:= b#16#2;//b#16#1; // Für IM151-8 PN/DP - ggf. anzupassen
T_PARAM.LOCAL_TSAP_ID_LEN:= 2;
T_PARAM.LOCAL_TSAP_ID[1]:= b#16#2E;//0;
T_PARAM.LOCAL_TSAP_ID[2]:= b#16#E0;//0;
T_PARAM.REM_TSAP_ID_LEN:= 2;
T_PARAM.REM_TSAP_ID[1]:= b#16#2E;//0;
T_PARAM.REM_TSAP_ID[2]:= b#16#E1;//0;
T_PARAM.ACTIVE_EST:= TRUE;
//T_PARAM.REM_TSAP_ID[2]:= 80; // Port eintragen - HTTP = 80
//T_PARAM.REM_TSAP_ID[1]:=0;
//T_PARAM.REM_TSAP_ID_LEN:= 2;
T_PARAM.REM_STADDR_LEN:= 4;
T_PARAM.REM_STADDR[1]:= INT_TO_BYTE(IP_ADDR1);
T_PARAM.REM_STADDR[2]:= INT_TO_BYTE(IP_ADDR2);
T_PARAM.REM_STADDR[3]:= INT_TO_BYTE(IP_ADDR3);
T_PARAM.REM_STADDR[4]:= INT_TO_BYTE(IP_ADDR4);

// Verbindung herstellen
T_CONN(REQ := CONNECT
,ID := CONNECTION_ID
,CONNECT := T_PARAM
);

CONNEC_STATUS := WORD_TO_INT(T_CONN.STATUS);


// Wenn T_CONN Done ausgibt, Verbunden melden
IF T_CONN.DONE THEN
CONNECTED := TRUE;
END_IF;


// T_CONN braucht eine Flanke am eingang REQ, daher erst
// nach dem ersten Zyklus auf True setzen
CONNECT:=TRUE;


END_IF;


// Daten empfangen
// ####################################################################################################
T_RCV(EN_R := CONNECTED
,ID := CONNECTION_ID
,LEN := 0 // Laenge 0 = Sofort empfangen - ggf. muss > 0 eingetragen werden
,DATA := RECV
);

RCV_STATUS := WORD_TO_INT(T_RCV.STATUS);

// Daten senden
// ####################################################################################################
T_SEND(REQ := SENDEN
,ID := CONNECTION_ID
,LEN := 47 // Laenge 47 Zeichen - Muss angepasst werden
,DATA := SEND
);

SEND_STATUS := WORD_TO_INT(T_SEND.STATUS);


// Daten senden wenn Verbunden ist, neue Daten empfangen wurden
// oder der Timeout angeschlagen hat
IF CONNECTED AND (T_RCV.NDR OR TIMEOUT_SEND.Q) THEN
SENDEN := TRUE;
END_IF;

// Bei erfolgreichem senden oder im Fehlerfall
// die Sendeanfrage zurücksetzen
IF T_SEND.DONE OR T_SEND.ERROR THEN
SENDEN := FALSE;
END_IF;

// Nach 5 Sek Send erneut antriggern
TIMEOUT_SEND(IN:=SENDEN,PT:=t#5s);



// Sendedaten aufbereiten
// ####################################################################################################
// ####################################################################################################

// Beispiel als String : 'GET /BEISPIEL HTTP/1.1$RHost: 192.168.001.010 $N$N';

// Als Array of Char:

SEND[000] := 'G';
SEND[001] := 'E';
SEND[002] := 'T';
SEND[003] := ' ';
SEND[004] := '/';
SEND[005] := 'B';
SEND[006] := 'E';
SEND[007] := 'I';
SEND[008] := 'S';
SEND[009] := 'P';
SEND[010] := 'I';
SEND[011] := 'E';
SEND[012] := 'L';
SEND[013] := ' ';
SEND[014] := 'H';
SEND[015] := 'T';
SEND[016] := 'T';
SEND[017] := 'P';
SEND[018] := '/';
SEND[019] := '1';
SEND[020] := '.';
SEND[021] := '1';
SEND[022] := '$R';
SEND[023] := 'H';
SEND[024] := 'o';
SEND[025] := 's';
SEND[026] := 't';
SEND[027] := ':';
SEND[028] := ' ';
SEND[029] := '1';
SEND[030] := '9';
SEND[031] := '2';
SEND[032] := '.';
SEND[033] := '1';
SEND[034] := '6';
SEND[035] := '8';
SEND[036] := '.';
SEND[037] := '0';
SEND[038] := '0';
SEND[039] := '1';
SEND[040] := '.';
SEND[041] := '0';
SEND[042] := '1';
SEND[043] := '0';
SEND[044] := ' ';
SEND[045] := '$R';
SEND[046] := '$R';

// Empfangsdaten auswerten
// ####################################################################################################
// ####################################################################################################

// Neue Daten angekommen
IF T_RCV.NDR THEN

// Hier auswerten
;

END_IF;


END_FUNCTION_BLOCK
 
Code for B&R (Client)

(********************************************************************
* COPYRIGHT -- Bernecker + Rainer
********************************************************************
* Program: Client
* File: Client.st
* Author: Bernecker + Rainer
* Created: February 21, 2008
********************************************************************
* Implementation of program Client
********************************************************************)

PROGRAM _CYCLIC

LibAsTCP1_ST.send_data[0] := LibAsTCP1_ST.send_data[0] + 1; (* Generate a "running" variable for Data transfer *)

CASE Client.sStep OF

0: (* Open Ethernet Interface *)
Client.TcpOpen_0.enable := 1;
Client.TcpOpen_0.pIfAddr := 0; (* Which Interface to open *)
Client.TcpOpen_0.port := 12001; (* Port on client side to use *)
Client.TcpOpen_0.options := 0;
Client.TcpOpen_0; (* Call the Function *)

IF Client.TcpOpen_0.status = 0 THEN (* TcpOpen successfull *)
Client.sStep := 5;
ELSIF Client.TcpOpen_0.status = ERR_FUB_BUSY THEN (* TcpOpen not finished -> redo *)
(* Busy *)
ELSE (* Goto Error Step *)
Client.sStep := 100;
END_IF

5:
Client.linger_opt.lLinger := 0; (* linger Time = 0 *)
Client.linger_opt.lOnOff := 1; (* linger Option ON *)

Client.TcpIoctl_0.enable := 1;
Client.TcpIoctl_0.ident := Client.TcpOpen_0.ident; (* Connection Ident from AsTP.TCP_Open *)
Client.TcpIoctl_0.ioctl := tcpSO_LINGER_SET; (* Set Linger Options *)
Client.TcpIoctl_0.pData := ADR(Client.linger_opt);
Client.TcpIoctl_0.datalen := SIZEOF(Client.linger_opt);
Client.TcpIoctl_0;

IF Client.TcpIoctl_0.status = 0 THEN (* TcpIoctl successfull *)
Client.sStep := 10;
ELSIF Client.TcpIoctl_0.status = ERR_FUB_BUSY THEN (* TcpIoctl not finished -> redo *)
(* Busy *)
ELSE (* Goto Error Step *)
Client.sStep := 100;
END_IF


10: (* Connect to the other Station *)
Client.TcpClient_0.enable := 1;
Client.TcpClient_0.ident := Client.TcpOpen_0.ident; (* Connection Ident from AsTCP.TCP_Open *)
Client.TcpClient_0.portserv := 12000; (* Port on server side to use *)
Client.TcpClient_0.pServer := ADR('192.168.100.158'); (* Server Address *)
Client.TcpClient_0(); (* Call the Function*)

IF Client.TcpClient_0.status = 0 THEN (* Open ok -> Send Data *)
Client.sStep := 20;
ELSIF Client.TcpClient_0.status = ERR_FUB_BUSY THEN (* TcpClient not finished -> redo *)
(* Busy *)
ELSIF Client.TcpClient_0.status = tcpERR_INVALID THEN (* Port error -> Close actual connection, and reopen a new one *)
Client.sStep := 40;
ELSE (* Goto Error Step *)
Client.sStep := 100;
END_IF

20: (* Send Data to the Server *)
Client.TcpSend_0.enable := 1;
Client.TcpSend_0.ident := Client.TcpOpen_0.ident; (* Connection Ident from AsTCP.TCP_Open *)
Client.TcpSend_0.pData := ADR(LibAsTCP1_ST.send_data); (* Which data to send *)
Client.TcpSend_0.datalen := SIZEOF(LibAsTCP1_ST.send_data); (* Lenght of data to send *)
Client.TcpSend_0.flags := 0;
Client.TcpSend_0; (* Call the Function*)

IF Client.TcpSend_0.status = 0 THEN (* Data was sent sucessfully -> receive data *)
Client.sStep := 50;
ELSIF Client.TcpSend_0.status = ERR_FUB_BUSY THEN (* TcpSend not finished -> redo *)
(* Busy *)
ELSIF (Client.TcpSend_0.status = tcpERR_SENTLEN) OR (Client.TcpSend_0.status = tcpERR_NOT_CONNECTED) THEN (* Connection Lost *)
Client.sStep := 40;
ELSE (* Goto Error Step *)
Client.sStep := 100;
END_IF

30: (* Receive Data from the Server *)
Client.TcpRecv_0.enable := 1;
Client.TcpRecv_0.ident := Client.TcpOpen_0.ident; (* Connection Ident from AsTCP.TCP_Open *)
Client.TcpRecv_0.pData := ADR(LibAsTCP1_ST.receive_data); (* Where to store the incoming data *)
Client.TcpRecv_0.datamax := SIZEOF(LibAsTCP1_ST.receive_data); (* Lenght of data buffer *)
Client.TcpRecv_0.flags := 0;
Client.TcpRecv_0; (* Call the Function*)

IF Client.TcpRecv_0.status = 0 THEN (* Data was received sucessfully -> Send next packet *)
Client.sStep := 50;
Client.recv_timeout := 0;
ELSIF Client.TcpRecv_0.status = tcpERR_NO_DATA THEN (* No data received - wait *)
Client.recv_timeout := Client.recv_timeout + 1;
IF Client.recv_timeout > 50 THEN
Client.sStep := 40;
Client.recv_timeout := 0;
END_IF
(* No Data received *)
ELSIF Client.TcpRecv_0.status = ERR_FUB_BUSY THEN (* TcpRecv not finished -> redo *)
(* Busy *)
ELSIF Client.TcpSend_0.status = tcpERR_NOT_CONNECTED THEN (* Connection Lost *)
Client.sStep := 40;
ELSE (* Goto Error Step *)
Client.sStep := 100;
END_IF

40: (* Close connection *)
Client.TcpClose_0.enable := 1;
Client.TcpClose_0.ident := Client.TcpOpen_0.ident; (* Connection Ident from AsTCP.TCP_Open *)
Client.TcpClose_0.how := 0;
Client.TcpClose_0; (* Call the Function*)

IF Client.TcpClose_0.status = 0 THEN (* Close sucessfull -> Reopen the interface *)
Client.sStep := 0;
ELSIF Client.TcpClose_0.status = ERR_FUB_BUSY THEN (* TcpClose not finished -> redo *)
(* Busy *)
ELSE (* Goto Error Step *)
Client.sStep := 100;
END_IF

100: (* Here some error Handling has to be implemented *)
Client.sStep := 0;

END_CASE


END_PROGRAM
 
While doing this raw socket communication will work, B&R PLCs have the ability to create Modbus TCP registers and treat them like they are IO. No programming required, you just turn on modbus communication for that ethernet port and configure the registers. You could simply use several consecutive registers to map an array of USINT on the B&R side and memcpy it over to a string. I assume Siemens also has canned Modbus TCP functionality.

As for the client side, you can add a generic Modbus device to the hardware tree and configure it's registers, so the Siemens could either be Client or Server, as long as it can do one or the other.
 
While doing this raw socket communication will work, B&R PLCs have the ability to create Modbus TCP registers and treat them like they are IO. No programming required, you just turn on modbus communication for that ethernet port and configure the registers. You could simply use several consecutive registers to map an array of USINT on the B&R side and memcpy it over to a string. I assume Siemens also has canned Modbus TCP functionality.

As for the client side, you can add a generic Modbus device to the hardware tree and configure it's registers, so the Siemens could either be Client or Server, as long as it can do one or the other.

In the newer PLC families (1200/1500) Modbus TCP blocks come included.

In the older PLCs (300/400), they are blocks that you have to buy a license for.
 

Similar Topics

Hi! I am using an M200 PLC connected by Modbus TCP/IP with a Com'X 510 energy server. I need to read the data corresponding to the voltage of a...
Replies
0
Views
1,032
Hello everyone, I got stuck on Communication with DL06/DL260 (H0_ECOM or ECOM100) through Modbus TCP. To make it simple I only read holding...
Replies
0
Views
1,400
Hello, I use a Beckhoff PLC to control an industrial robot. The CAD data come from a main computer which control the whole factory. The main...
Replies
1
Views
2,694
Hi, We have an application that has a device that goes through a reboot (appears un-graceful) What then happens is the MVI module appears to hang...
Replies
0
Views
49
I am very new to Modbus and the industry, so forgive me if I am missing something obvious. I have known Modbus register addresses coming from a...
Replies
7
Views
199
Back
Top Bottom