FUNCTION_BLOCK "FB_TcpCommServer"
{ S7_Optimized_Access := 'TRUE' }
AUTHOR : SiemensAG
FAMILY : OpenUserComm
VERSION : 1.0
   VAR_INPUT 
      enable : Bool;   // enables TCP/IP connection
      sendRequest : Bool;   // triggers a send request
      rcvLen : UDInt;   // length of data you want to receive from partner (opt. DBs = 0)
      sendLen : UDInt;   // length of date so send to partner
      adhocMode : Bool;   // activate adhoc Mode to receive data with variable len
      tcpConnParam {InstructionName := 'TCON_IP_v4'; LibVersion := '1.0'} : TCON_IP_v4;   // Connection Parameters
   END_VAR

   VAR_OUTPUT 
      connectionEstablished : Bool;   // connection to partner established
      ndr : Bool;   // new data received
      done : Bool;   // send request finished successully
      busy : Bool;   // block is busy
      error : Bool;   // error occurred
      rcvdLen : UDInt;   // length of received data (in byte)
      statusID : UInt;   // error location in block
      status : Word;   // status word from OUC blocks
   END_VAR

   VAR_IN_OUT 
      sendData : Array[*] of Byte;   // data to send to partner
      rcvData : Array[*] of Byte;   // received data from partner
   END_VAR

   VAR 
      instTcon {InstructionName := 'TCON'; LibVersion := '4.0'} : TCON;
      instTdiscon {InstructionName := 'TDISCON'; LibVersion := '2.1'} : TDISCON;
      instTrcv {InstructionName := 'TRCV'; LibVersion := '4.0'} : TRCV;
      instTsend {InstructionName := 'TSEND'; LibVersion := '4.0'} : TSEND;
      statTcpConnParam {InstructionName := 'TCON_IP_v4'; LibVersion := '1.0'} : TCON_IP_v4;
      instTimer {InstructionName := 'TON_TIME'; LibVersion := '1.0'} : TON_TIME;
      statStartTimer : Bool;
      statStoppTimer : Bool;
      statTimeRun : Time;
      statEdgeCon : Bool;
      statEdgeConOld : Bool;
      statEdgeDiscon : Bool;
      statEdgeDisconOld : Bool;
      statEdgeSendReq : Bool;
      statEdgeSendReqOld : Bool;
      statConnID : Word;
      statConActive : Bool;
      statStateValue : Int;
      statStatus : Word;
      statStatusId : UInt;
      statConReEstablish : Bool;
      statSendActive : Bool;
      statPartnerDisconnected : Bool;
      statTimerEnd : Bool;
      statErrorIntern : Bool;
      statDataBufferRcv : Array[1..65536] of Byte;
      statRcvdLen : UDInt;
      statRcvLen : UDInt;
      statRcvFrameLen : DInt;
      statRcvFrameLenSave : DInt;
      statRcvBusy : Bool;
      statCntRecv : Int;
      statRcvDataLen : DWord;
      statNdr : Bool;
      statLenDetected : Bool;
      statCntNdr : UInt;
      statRcvLenTest : UDInt;
      statLowerBoundSend : DInt;
      statLowerBoundRcv : DInt;
      statUpperBoundSend : DInt;
      statUpperBoundRcv : DInt;
      statRcvdLenNotDetected : Bool;
   END_VAR

   VAR_TEMP 
      tempRetVal : Int;
      tempPos : DInt;
   END_VAR

   VAR CONSTANT 
      STATE_IDLE : Int := 1;   // idle mode - wating for events
      STATE_PARAM : Int := 2;   // take over IsoOnTcp parameters
      STATE_CONNECT : Int := 3;   // establish IsoOnTcp connection
      STATE_DISCONNECT : Int := 4;   // disconnect IsoOnTcp connection
      STATE_SEND : Int := 5;   // send data to partner
      STATE_RECEIVE : Int := 6;   // receive data
      STATE_CONNECTED : Int := 7;   // connection established
      STATE_ERROR : Int := 8;   // error state
      STATUS_ID_INT_ERROR : UInt := 1;   // error location state - initialization
      STATUS_ID_CON : UInt := 2;   // error location state - connect
      STATUS_ID_DISCON : UInt := 5;   // error location - disconnect
      STATUS_ID_SEND : UInt := 4;   // error location -send data
      STATUS_ID_RCV : UInt := 3;   // error location - receive data
      ERR_COMM_NOT_STARTED : Word := 16#8101;   // communication not startet
      ERR_WATCHDOG_TIMER : Word := 16#8102;   // watchdog timer expired
      ERR_COMM_ID_IN_USE : Word := 16#80A3;   // connection ID is already used (TCON)
      ERR_COMM_TEMP : Word := 16#80C4;   // temporary communication error
      ERR_COMM_TCON_NOT_COMPLETED : Word := 16#80A7;   // executed "TDISCON" before "TCON" had completed
      ERR_COMM_PARTNER_TERMINATE_CONNETION : Word := 16#80C5;   // connection partner refuses to establish connection or terminated connection actively
      ERR_COMM_CONNECTION_NOT_EXIST : Word := 16#80A3;   // connection does exist (TDISCON)
      ERR_COMM_CONNECTION_TERMINATED : Word := 16#80A1;   // communication already terminated
      CONST_LEN_HEADER : UDInt := 4;
      CONST_WATCHDOG_TIME : Time := T#180s;   // watchdog time
      CONST_WORD_0 : Word := 16#0000;
      CONST_UINT_0 : UInt := 0;
      CONST_UDINT_0 : UDInt := 0;
      CONST_DINT_0 : DInt := 0;
      CONST_MAX_RCVD_DATA_LEN : UDInt := 65536;
      CONST_MIN_RCVD_DATA_LEN : UDInt := 0;
   END_VAR


BEGIN
	//=============================================================================
	//SIEMENES AG
	//(c)Copyright 2020 All Rights Reserved
	//-----------------------------------------------------------------------------
	//Library:       LOpenUserComm
	//Tested with:   (S7-1500 V2.8; S7-1200 V4.4)
	//Engineering:    TIA Portal V16
	//Restrictions:   call in cyclic main OB
	//Requirements:
	//Functionality: Open User Communication Template for TCP connections
	//               Shows the basic steps to use the OUC blocks to establish
	//               reliable TCP/IP connections in an state machine
	//               ....
	//NEUER TEST
	//-----------------------------------------------------------------------------
	//Change log table:
	//Version  Date       Expert in charge Changes applied
	//01.01.02 18.02.2020 (DI CS SD CSS KMT) Update of the released version V1.1.1
	//=============================================================================
	
	
	#statLowerBoundSend:=LOWER_BOUND(ARR := #sendData, DIM := 1);
	#statLowerBoundRcv:= LOWER_BOUND(ARR:=#rcvData, DIM:=1);
	#statUpperBoundSend := UPPER_BOUND(ARR := #sendData, DIM := 1);
	#statUpperBoundRcv := UPPER_BOUND(ARR := #rcvData, DIM := 1);
	
	REGION edgeDetection 
	    
	    //evaluluate pos edge on input enable for connection establishment
	    #statEdgeCon := #enable AND NOT
	    #statEdgeConOld;
	    #statEdgeConOld := #enable;
	    
	    //evaluluate neg edge on input enable for connection termination
	    #statEdgeDiscon := NOT #enable AND
	    #statEdgeDisconOld;
	    #statEdgeDisconOld := #enable;
	    
	    //evaluluate pos edge on input sendRequest
	    #statEdgeSendReq := #sendRequest AND NOT
	    #statEdgeSendReqOld;
	    #statEdgeSendReqOld := #sendRequest;
	    
	END_REGION
	
	REGION initStates // evaluates the correct init state due to the input parameters
	    
	    //establish connection to partner
	    IF (#statEdgeCon = true)
	    THEN
	        IF (#busy = false)
	        THEN
	            #busy := true;
	            #statStateValue := #STATE_PARAM;
	        ELSE
	            #statStatusId := #STATUS_ID_INT_ERROR; // internal initialization error
	            #statStatus := #ERR_COMM_NOT_STARTED; // 16#8101: communication not startet 
	            #statStateValue := #STATE_ERROR;
	        END_IF;
	    END_IF;
	    
	    //If disconnect required, set state to STATE_DISCONNECT
	    IF (#statEdgeDiscon = true)
	    THEN
	        #statStateValue := #STATE_DISCONNECT;
	    END_IF;
	    
	    //If sendRequest is required and connection is established set state to STATE_SEND
	    IF ((#statEdgeSendReq = true)
	        AND (#statConActive = true))
	    THEN
	        #statStateValue := #STATE_SEND;
	    END_IF;
	    
	    // Watchdog timer to supervise connection
	    #instTimer(IN := #statStartTimer,
	               PT := #CONST_WATCHDOG_TIME,
	               Q => #statStoppTimer,
	               ET => #statTimeRun);
	    
	    // Go to state STATE_DISCONNECT when watchdog timer expired during connection establishment.
	    IF (#statStoppTimer = true)
	    THEN
	        #error := false;
	        #statStartTimer := false; //reset watchdog timer
	        #statTimerEnd := true;  // trigger watchdog timer is expired
	        #statStateValue := #STATE_DISCONNECT; //when watchdog timer is expired got to STATE_DISCONNECT for connection termination
	    END_IF;
	    
	END_REGION
	
	REGION stateMachine // contains the state machine
	    // TCP/IP management
	    // This section manages all the states to handle the Open User Communication blocks in a coordinated state machine.
	    
	    CASE #statStateValue OF
	        #STATE_IDLE:  // idle mode, waiting for events
	            
	            #busy := false;
	            #error := false;
	            #status := #CONST_WORD_0;
	            #statusID := #CONST_UINT_0;
	            #statStatus := #CONST_WORD_0;
	            #statStatusId := #CONST_UINT_0;
	            #ndr := false;
	            #done := false;
	            #rcvdLen := #CONST_UDINT_0;
	            #statRcvdLen := #CONST_UDINT_0;
	            #statRcvFrameLen := #CONST_DINT_0;
	            #connectionEstablished := false;
	            #statStartTimer := false;  //reset watchdog timer
	            #instTcon.REQ := false; //stop all TCON activities
	            #instTdiscon.REQ := false; //stop all TDISCON activities
	            #instTrcv.EN_R := false; // stop all TRCV activities
	            #statSendActive := false;
	            
	        #STATE_PARAM:  // read connection parameters from input
	            
	            #instTcon.REQ := false; //stop all TCON activities
	            #instTdiscon.REQ := false; //stop all TDISCON activities
	            #instTrcv.EN_R := false; // stop all TRCV activities
	            #statTcpConnParam := #tcpConnParam; //connection parameters
	            #statConnID := #statTcpConnParam.ID; //unique connection ID
	            #statStateValue := #STATE_CONNECT; //set state machine to STATE_CONNECT
	            
	        #STATE_CONNECT: //establish connection
	            
	          REGION connect
	                
	                IF (#statConActive = false) //no active connection
	                THEN
	                    #instTcon.REQ := true; //activate TCON block
	                    #statStartTimer := true; //activate watchdog timer to supervise connection process
	                ELSIF (#statConActive = true) //connection already active
	                THEN
	                    #statStateValue := #STATE_CONNECTED;  //set state machine to STATE_CONNECTED
	                END_IF;
	                
	                IF ((#instTcon.DONE = TRUE)
	                    AND (#instTcon.BUSY = FALSE)) //connection is established
	                THEN
	                    #instTcon.REQ := false;
	                    #statStartTimer := false;  //reset watchdog timer
	                    #statConActive := true;    //conenction is active
	                ELSIF (#instTcon.ERROR = true)   //error on establishing Tcp connection
	                THEN
	                    //prepare error location information
	                    #instTcon.REQ := false;
	                    #statStatusId := #STATUS_ID_CON; //error occurred while establishing connection
	                    #statStatus := #instTcon.STATUS; //error code from OUC block TCON
	                    #statStateValue := #STATE_ERROR;  // set state machine to STATE_ERROR while connection establishment
	                END_IF;
	                
	            END_REGION
	            
	        #STATE_DISCONNECT: //disconnect connection
	            
	          REGION disconnect
	                
	                //TDISCON is activated:
	                IF ((#statConActive = true) //when disconnect is required by input enable=0 and conenction is active,
	                    OR (#statConReEstablish = true) //before connection is re-established
	                    OR (#statTimerEnd = true)) //when watch dog timer is expired
	                THEN
	                    #instTdiscon.REQ := true;  //activate TDISCON block
	                ELSIF (#statConActive = false)  // connection is not active
	                THEN
	                    #statStateValue := #STATE_IDLE; //go to STATE_IDLE because connection is not active
	                END_IF;
	                
	                IF (#instTdiscon.DONE = TRUE)
	                THEN
	                    #instTdiscon.REQ := false;  //conenction is disconnected
	                    #statConActive := false;  // connection isn`t active
	                    #statConReEstablish := false; //reset trigger for connection termination before re-establishment
	                END_IF;
	                
	                IF (#instTdiscon.ERROR = true) //error on disconnecting Tcp connection
	                THEN
	                    //prepare error location information
	                    #instTdiscon.REQ := false;
	                    #statStatus := #instTdiscon.STATUS; //error code from OUC block TDISCON
	                    #statStatusId := #STATUS_ID_DISCON; //error occurred while disconnecting connection
	                    #statStateValue := #STATE_ERROR; // set state machine to STATE_ERROR while connection termination
	                    #statConReEstablish := false; //reset trigger for connection termination before re-establishment
	                END_IF;
	                
	            END_REGION
	            
	        #STATE_CONNECTED: //connection is successful established to partner
	            
	            REGION connected
	                // REGION connected
	                
	                #done := false;
	                #ndr := false; //reset output ndr=0
	                #busy := true;
	                #rcvdLen := #CONST_UINT_0; // reset output rcvdLen=0;
	                #instTrcv.EN_R := true;  //activate TRCV block for incoming telegrams
	                #connectionEstablished := NOT (#statPartnerDisconnected);
	                #statRcvdLenNotDetected := false;
	                
	                IF #adhocMode = TRUE
	                THEN
	                    #statRcvLen := 0;
	                ELSIF #adhocMode=FALSE
	                THEN
	                    #statRcvLen := #rcvLen;
	                END_IF;
	                
	                IF (#instTrcv.NDR = TRUE) //New Data Received
	                THEN
	                    
	                    IF #statCntNdr >= 50
	                    THEN
	                        #statCntRecv := 0;
	                    END_IF;
	                        
	                    #statCntNdr := #statCntNdr + 1;
	                    
	                    #statRcvdLen := #instTrcv.RCVD_LEN; // set output rcvdLen to the length of received data
	                    #statRcvLenTest := #instTrcv.RCVD_LEN;
	                    
	                    #statStateValue := #STATE_RECEIVE;
	                    
	                ELSIF (#instTrcv.ERROR = true)            // error occurred on receiving data in block TRCV
	                THEN
	                    //prepare error location information
	                    #statStatusId := #STATUS_ID_RCV;    //error occurred while receiving data
	                    #statStatus := #instTrcv.STATUS;    //error code from OUC block TRCV
	                    #statStateValue := #STATE_ERROR;    // set state machine to STATE_ERROR while receiving data
	                ELSE
	                    #status := #CONST_WORD_0;
	                    #statusID := #CONST_UINT_0;
	                    #error := false;
	                    #statPartnerDisconnected := false;
	                END_IF;
	                
	            END_REGION
	            
	        #STATE_SEND: //send data to partner
	            
	          REGION sendData
	                
	                
	                IF (#statSendActive = false)
	                THEN
	                    #instTsend.REQ := true;  //activate TSEND block
	                    #statSendActive := true; //send job is active (no other request to sendRequest is possible)
	                END_IF;
	                
	                IF (#instTsend.DONE) // data send successfully
	                THEN
	                    #statSendActive := false;               // no send job active
	                    #statStateValue := #STATE_CONNECTED;    // set state to STATE_CONNECTED
	                    #done := true;                          // send request is finished successfully
	                    #busy := false;                         // set busy=false
	                ELSIF #instTsend.ERROR = true //error on send data
	                THEN
	                    //prepare error location information
	                    #statSendActive := false;
	                    #statStatusId := #STATUS_ID_SEND; //error occurred while sending data
	                    #statStatus := #instTsend.STATUS; //error code from OUC block TSEND
	                    #statStateValue := #STATE_ERROR; // set state machine to STATE_ERROR while sending data
	                END_IF;
	                
	            END_REGION
	            
	        #STATE_RECEIVE:
	            
	            REGION receiveData
	                
	                // handle here the received data individual for your purposes
	                // in this template received data is simply copied to paramter #rcvData
	                
	                // adhoc mode is activated
	                IF #adhocMode = TRUE
	                THEN
	                    
	                  IF #statLenDetected = FALSE
	                  // THEN
	                  //   #statRcvDataLen.%B0 := #statDataBufferRcv[4];
	                  //   #statRcvDataLen.%B1 := #statDataBufferRcv[3];
	                  //   #statRcvDataLen.%B2 := #statDataBufferRcv[2];
	                  //   #statRcvDataLen.%B3 := #statDataBufferRcv[1];
	                    
	                  //   IF (DWORD_TO_UDINT(#statRcvDataLen) >= #CONST_MIN_RCVD_DATA_LEN)
	                  //     AND (DWORD_TO_UDINT(#statRcvDataLen) <= #CONST_MAX_RCVD_DATA_LEN)
	                    THEN
	                        #statLenDetected := true;
	                      #tempRetVal := MOVE_BLK_VARIANT(SRC := #statDataBufferRcv,
	                                                      COUNT := #statRcvdLen,
	                                                      SRC_INDEX := #CONST_DINT_0,
	                                                      DEST_INDEX := #CONST_DINT_0,
	                                                      DEST => #rcvData);
	                    // ELSE
	                      
	                    //   #rcvdLen := 0;
	                    //   #statRcvFrameLen := 0;
	                    //   #statRcvdLen := 0;
	                    //   #statRcvdLenNotDetected := true;
	                    // END_IF;
	                    
	                  ELSE
	                    
	                    
	                    #tempRetVal := MOVE_BLK_VARIANT(SRC := #statDataBufferRcv,
	                                                    COUNT := #statRcvdLen,
	                                                    SRC_INDEX := #CONST_DINT_0,
	                                                    DEST_INDEX := #statRcvFrameLen,
	                                                    DEST => #rcvData);
	                  END_IF;
	                    
	                    
	                    #statRcvFrameLen := #statRcvFrameLen + UDINT_TO_DINT(#statRcvdLen);
	                    
	                    IF (#statRcvFrameLen >= #statRcvDataLen)
	                      AND (#statRcvdLenNotDetected = false)
	                    THEN
	                      #statRcvFrameLenSave := #statRcvFrameLen;
	                      #rcvdLen := DINT_TO_UDINT(#statRcvFrameLen);
	                      #statRcvFrameLen := 0;
	                      #statRcvdLen := 0;
	                      #statLenDetected := false;
	                      #ndr := true;
	                    END_IF;
	                    
	                    //adhoc mode is deactivated    
	                ELSE
	                    
	                    #tempRetVal := MOVE_BLK_VARIANT(SRC := #statDataBufferRcv,
	                                                    COUNT := #statRcvdLen,
	                                                    SRC_INDEX := 0,
	                                                    DEST_INDEX := 0,
	                                                    DEST => #rcvData);
	                    
	                    
	                    #ndr := true;
	                    #rcvdLen := #statRcvdLen;
	                    
	                END_IF;
	                
	                IF #statCntRecv >= 50
	                THEN
	                    #statCntRecv := 0;
	                END_IF;
	                
	                #statCntRecv := #statCntRecv + 1;
	                
	                
	                #statStateValue := #STATE_CONNECTED;
	             
	                
	            END_REGION
	            
	        #STATE_ERROR: // error handling
	            
	            REGION errorHandling
	                
	                //Error source: occurred in STATE_CONNECT - establishing connection
	                IF (#statStatusId = #STATUS_ID_CON)
	                THEN
	                    
	                    // re-establishment of connection nesccessary when:
	                    IF ((#statStatus = #ERR_COMM_ID_IN_USE) //16#80A3 ID is used by a connection created by the user program, which uses the same connection description at the CONNECT parameter.
	                        OR (#statStatus = #ERR_COMM_TCON_NOT_COMPLETED))  // 16#80A7 Communication error: You executed "TDISCON" before "TCON" had completed. 
	                    THEN
	                        #statConReEstablish := true; //trigger for re-establishment
	                        #statStateValue := #STATE_DISCONNECT;  // set state to STATE_DISCONNECT for connection termination before re-establishment
	                        
	                    // go to STATE_CONNECT again, when client isn`t connected  
	                    //16#80C5: connection partner refuses to establish connection or terminated connection actively.    
	                    ELSIF (#statStatus = #ERR_COMM_PARTNER_TERMINATE_CONNETION) 
	                    THEN
	                        #statStateValue := #STATE_CONNECT;  // set state to STATE_CONNECT
	                        #statErrorIntern := true;
	                    ELSE
	                        #statStateValue := #STATE_IDLE; //set state to STATE_IDLE in any other error cases and wait for new user events
	                    END_IF;
	                    
	                //Error source: occurred in STATE_DISCONNECT -  disconnecting connection    
	                ELSIF (#statStatusId = #STATUS_ID_DISCON)
	                THEN
	                    
	                    IF (#statStatus = #ERR_COMM_CONNECTION_NOT_EXIST) // 16#80A3 Connection doesn`t exist or isn`t established
	                    THEN
	                        
	                        //When watchdog timer is expired connection isn`t established. TDISCON shows status 16#80A3.
	                        //In this case change error location information
	                        IF (#statTimerEnd = TRUE)
	                        THEN
	                            #statTimerEnd := false;  //reset trigger watchdog timer expired
	                            #statStatusId := #STATUS_ID_INT_ERROR; //internal error
	                            #statStatus := #ERR_WATCHDOG_TIMER;   //16#8102 watchdog timer is expired
	                        END_IF;
	                        
	                        #statConActive := false;  //no active connection
	                        #statStateValue := #STATE_IDLE;  //When status 16#80A3 isn`t cause by watchdog timmer go to STATE_IDLE
	                    ELSE
	                        #statStateValue := #STATE_DISCONNECT; // in any other error cases go to STATE_DISCONNECT for connection termination
	                    END_IF;
	                    
	                //Error source: occurred in STATE_CONNECTED - receive new data    
	                ELSIF #statStatusId = #STATUS_ID_RCV
	                THEN
	                    
	                    // connection is terminated or temporary communication error
	                  IF ((#statStatus = #ERR_COMM_TEMP)
	                    OR (#statStatus = #ERR_COMM_CONNECTION_TERMINATED))
	                  THEN
	                    
	                    IF (#enable = true) //when input enable = true partner has terminated the connection
	                    THEN
	                      #statPartnerDisconnected := true; // trigger that partner has disconnected the connection
	                      #statErrorIntern := true;  // Trigger internal Error -> no action by user neccessary
	                      #statStateValue := #STATE_CONNECTED; // when partner has terminated connection stay in STATE_CONNECTED and wait for the partner
	                    ELSE    // connection termination was required via input enable = 0
	                      #statStateValue := #STATE_IDLE; // set state to IDLE_STATE
	                    END_IF;
	                    
	                    // The partner has disconnected 
	                  ELSIF (#statStatus = #ERR_COMM_PARTNER_TERMINATE_CONNETION)
	                  THEN
	                    #statPartnerDisconnected := true; // trigger that partner has disconnected the connection
	                    #statErrorIntern := true;     // Trigger internal Error -> no action by user neccessary
	                    #statStateValue := #STATE_CONNECTED; // when partner has terminated connection stay in STATE_CONNECTED and wait for the partner
	                    
	                  ELSE //any other error cases
	                    #statStateValue := #STATE_DISCONNECT; //set state to STATE_DISCONNECT for connection termination
	                  END_IF;
	                    
	                ELSIF (#statStatusId = #STATUS_ID_SEND) //Error source: occurred in STATE_SEND - send data
	                THEN
	                    // connection is terminated or temporary communication error
	                    IF ((#statStatus = #ERR_COMM_TEMP)
	                        OR (#statStatus = #ERR_COMM_CONNECTION_TERMINATED))
	                    THEN
	                        
	                        IF (#enable = true) //when input enable = true partner has terminated the connection
	                        THEN
	                            #statPartnerDisconnected := true; //when input enable = true partner has terminated the connection
	                            #statErrorIntern := true; // Trigger internal Error -> no action by user neccessary
	                            #statStateValue := #STATE_CONNECTED; // when partner has terminated connection stay in STATE_CONNECTED and wait for the partner
	                        ELSE      // connection termination was required via input enable = 0
	                            #statStateValue := #STATE_IDLE; // set state to IDLE_STATE
	                        END_IF;
	                        
	                        // The partner has disconnected 
	                    ELSIF (#statStatus = #ERR_COMM_PARTNER_TERMINATE_CONNETION)
	                    THEN
	                        #statPartnerDisconnected := true; //when input enable = true partner has terminated the connection
	                        #statErrorIntern := true; // Trigger internal Error -> no action by user neccessary
	                        #statStateValue := #STATE_CONNECTED; // when partner has terminated connection stay in STATE_CONNECTED and wait for the partner
	                    ELSE //any other error cases 
	                        #statStateValue := #STATE_DISCONNECT; //set state to STATE_DISCONNECT for connection termination
	                    END_IF;
	                    
	                ELSIF (#statStatusId = #STATUS_ID_INT_ERROR)
	                THEN
	                    #statStateValue:=#STATE_IDLE;
	                END_IF;
	                
	                //set output parameters
	                IF (#statErrorIntern = true)     // internal error (no activity by the user neccessary)
	                THEN
	                    #statErrorIntern := false;
	                    #busy := true;   // do not reset the output busy (FB works)
	                ELSE  //other error cases
	                    #busy := false;  //reset output #busy (FB doesn't works) 
	                END_IF;
	                
	                #status := #statStatus;
	                #statusID := #statStatusId;
	                #error := true;
	                
	            END_REGION
	            
	        ELSE  // Statement section ELSE
	            #statStateValue := #STATE_IDLE;
	    END_CASE;
	    
	END_REGION
	
	REGION callOUCBlocks // call of all OUC blocks
	  
	  // TCON 
	  #instTcon(ID := #statConnID,
	            CONNECT := #statTcpConnParam);
	  
	  // TDISCON
	  #instTdiscon(ID := #statConnID);
	  
	  // TRCV
	  #instTrcv(ID := #statConnID,
	            ADHOC := #adhocMode,
	            LEN := #statRcvLen,
	            DATA := #statDataBufferRcv);
	  
	  //TSEND
	  #instTsend(ID := #statConnID,
	             LEN := #sendLen,
	             DATA := #sendData);
	  
	  #instTsend.REQ := false;
	  
	END_REGION
END_FUNCTION_BLOCK

