FUNCTION_BLOCK "FB_CommunicationWES_ASRS"
{ S7_Optimized_Access := 'TRUE' }
VERSION : 0.1
   VAR_IN_OUT 
      fbInOutSendFIFO : "LGF_FIFO";
      arFifoSendBuffer : Array[1..100] of "UDT_TelegramData_Send";
   END_VAR

   VAR 
      fbTeleHandler : "FB_TCP_LCOM_TeleHandler";
      xReset : Bool;
      xSendTele : Bool;
      stTelegramToSend : "UDT_TelegramData_Send";
      nStateReceive : Int;
      nStateSend : Int;
      xRetVal : Bool;
      stNewTelegram { S7_SetPoint := 'False'} : "UDT_TelegramData";
      stTeleBReqM : "UDT_Telegram_BReqM";
      rTrigConnectionActive {InstructionName := 'R_TRIG'; LibVersion := '1.0'} : R_TRIG;
      xSendHeartbeat : Bool;
      tOnHeartbeat {InstructionName := 'TON_TIME'; LibVersion := '1.0'} : TON_TIME;
      sTelegramKennung : String;
   END_VAR

   VAR_TEMP 
      EmptyData : "UDatenSend" := ([10('$00')], (), (), (), (), (), [()], [()]);
   END_VAR

   VAR CONSTANT 
      c0000_WaitingReceive : Int := 0;
      c0100_GetNewTelegram : Int := 100;
      c0200_AnalyzeTelegram : Int := 200;
      c0999_ErrorReceive : Int := 999;
      c0000_WaitingSend : Int := 0;
      c0100_PrepareSendTelegram : Int := 100;
      c0200_ClearSend : Int := 200;
      c0999_ErrorSend : Int := 999;
   END_VAR


BEGIN
	REGION Info
	  // Kommunikation zu Fortna WES/ASRS Driver
	    // Telegramme:
	        // Senden:
	            // BRRespM (Abruf Bestätigung/Update)  | Schönenberger -> Fortna WES/ASRS Driver
	            // BSRespM (Einlagern Bestätigung)     | Schönenberger -> Fortna WES/ASRS Driver
	        // Empfangen:
	            // BReqM (Abruf)                       | Fortna WES/ASRS Driver -> Schönenberger
	
	END_REGION
	
	// Fortna WES ASRS
	// IP: 172.22.160.21
	// Port: 30635
	
	REGION Call TeleHandler
	    // hardware identifier of the local interface, PLC tags--Default tag table--System constant default value: PROFINET_interface_1 = 64
	    #fbTeleHandler.stInTcpTypeConfig.connection.interfaceID := "Local~PN-Interface_Customer";
	    //unique connection identifier (W#16#0001...W#16#0FFF)
	    #fbTeleHandler.stInTcpTypeConfig.connection.connectionID := 71;
	    //used protocol: 1=TCP protocol, 2=LCom protocol
	    #fbTeleHandler.stInTcpTypeConfig.connection.comService := "LCOM_TCP_CONNECTION";
	    //FALSE: passive (server), TRUE: active connection establishment (client)
	    #fbTeleHandler.stInTcpTypeConfig.connection.isClient := TRUE;
	    //TRUE: accept requests from all partners, FALSE: only specified partner is allowed in case of server
	    #fbTeleHandler.stInTcpTypeConfig.connection.acceptUnknownPartner := TRUE;
	    //local port number (possible values: 1...49151; caution: some may be reserved for internal use; recommended values: 2000...5000)
	    #fbTeleHandler.stInTcpTypeConfig.connection.localPort := 30635;
	    //partner port number, use only in case of client or specified partner (possible values: 1...49151; recommended values: 2000...5000)
	    #fbTeleHandler.stInTcpTypeConfig.connection.partnerPort := 30635;
	    
	    //partner IP address xxx.xxx.xxx.xxx = [1].[2].[3].[4], use only in case of client or specified partner
	    #fbTeleHandler.stInTcpTypeConfig.connection.partnerIP.ADDR[1] := 172;
	    #fbTeleHandler.stInTcpTypeConfig.connection.partnerIP.ADDR[2] := 22;
	    #fbTeleHandler.stInTcpTypeConfig.connection.partnerIP.ADDR[3] := 160;
	    #fbTeleHandler.stInTcpTypeConfig.connection.partnerIP.ADDR[4] := 21;
	    
	    #fbTeleHandler.stInTcpTypeConfig.connection.connectType := "LCOM_CON_TYPE_IPV4";
	    
	    // Telegramdefinition
	    #fbTeleHandler.stInTelegramDefinition.sStartMarker := '$02';
	    #fbTeleHandler.stInTelegramDefinition.sEndMarker := '$03';
	    #fbTeleHandler.stInTelegramDefinition.sStartMarkerSend := '$02';
	    #fbTeleHandler.stInTelegramDefinition.sEndMarkerSend := '$03';
	    #fbTeleHandler.stInTelegramDefinition.bSeparatorByte := '$1D'; //',';
	    #fbTeleHandler.stInTelegramDefinition.nLength := 0;
	    #fbTeleHandler.stInTelegramDefinition.nTelegramIDDataField := 0;
	    #fbTeleHandler.stInTelegramDefinition.xTelegramIDIsNumber := FALSE;
	    
	    #fbTeleHandler(xInReset := #xReset,
	                   xInOutSendTele := #xSendTele,
	                   stInTelegramSend := #stTelegramToSend,
	                   fbInOutSendFIFO := #fbInOutSendFIFO,
	                   arFifoSendBuffer := #arFifoSendBuffer);
	END_REGION
	
	REGION Reset SequenceNumber
	    #rTrigConnectionActive(CLK := #fbTeleHandler.xOutConnectionActive);
	    
	    IF #rTrigConnectionActive.Q THEN
	        "DB_CommunicationParameters".nSeqNumWESASRS := 0;
	    END_IF;
	END_REGION
	
	REGION Send Heartbeat
	    IF #fbTeleHandler.xOutConnectionActive THEN
	        #xSendHeartbeat := TRUE;
	        
	        IF #tOnHeartbeat.Q THEN
	            #xSendHeartbeat := FALSE;
	            "FC_Send_HB"(sInPLCID := "cPLCID",
	                         nInPartnerType:= 3,
	                         FIFO := "DB_LGF_FIFO_CommWES_ASRS",
	                         BUFFER := "DB_Buffer_CommunicationWES_ASRS".BUFFER,
	                         nInOutSequenceNumber := "DB_CommunicationParameters".nSeqNumWESASRS);
	        END_IF;
	    ELSE
	        #xSendHeartbeat := FALSE;
	    END_IF;
	    
	    #tOnHeartbeat(IN := #xSendHeartbeat,
	                  PT := t#15s);
	END_REGION
	
	REGION Sendefach verwalten / Telegramme verschicken
	    //Handshake mit Andi Programm
	    CASE #nStateSend OF
	        0: //Waiting
	            IF "SS_Port1_SendDaten".Port1.TelegrammKennung[1] <> '$00' THEN
	                #nStateSend := 100;
	            END_IF;
	            
	        100: //Neues Telegramm
	            Chars_TO_Strg(Chars := "SS_Port1_SendDaten".Port1.TelegrammKennung,
	                          pChars := 0,
	                          Cnt := 0,
	                          Strg => #sTelegramKennung);
	            
	            IF #sTelegramKennung = 'BRRespM' THEN
	                "FC_Send_BRRespM"(sInPLCID := "cPLCID",
	                                  nInBarcode := "SS_Port1_SendDaten".Port1.TrolleyID,
	                                  nInReasonCode := "SS_Port1_SendDaten".Port1.Status_1,
	                                  nInBufferLaneId := "SS_Port1_SendDaten".Port1.Puffer_LinienNr,
	                                  nInStoreGroup := "SS_Port1_SendDaten".Port1.StoreGroup,
	                                  FIFO := "DB_LGF_FIFO_CommWES_ASRS",
	                                  BUFFER := "DB_Buffer_CommunicationWES_ASRS".BUFFER,
	                                  nInOutSequenceNumber := "DB_CommunicationParameters".nSeqNumWESASRS);
	                
	                #nStateSend := 300;
	                
	            ELSIF #sTelegramKennung = 'BSRespM' THEN
	                "FC_Send_BSRespM"(sInPLCID := "cPLCID",
	                                  nInBarcode := "SS_Port1_SendDaten".Port1.TrolleyID,
	                                  nInReasonCode := "SS_Port1_SendDaten".Port1.Status_1,
	                                  nInBufferLaneId := "SS_Port1_SendDaten".Port1.Puffer_LinienNr,
	                                  nInStoreGroup := "SS_Port1_SendDaten".Port1.StoreGroup,
	                                  FIFO := "DB_LGF_FIFO_CommWES_ASRS",
	                                  BUFFER := "DB_Buffer_CommunicationWES_ASRS".BUFFER,
	                                  nInOutSequenceNumber := "DB_CommunicationParameters".nSeqNumWESASRS);
	                
	                #nStateSend := 300;
	            ELSE
	                #nStateSend := 999; // ERROR
	            END_IF;
	            
	        300: // Sendefach leeren
	            #EmptyData.TelegrammKennung[1] := '$00';
	            #EmptyData.TelegrammKennung[2] := '$00';
	            #EmptyData.TelegrammKennung[3] := '$00';
	            #EmptyData.TelegrammKennung[4] := '$00';
	            #EmptyData.TelegrammKennung[5] := '$00';
	            #EmptyData.TelegrammKennung[6] := '$00';
	            #EmptyData.TelegrammKennung[7] := '$00';
	            #EmptyData.TelegrammKennung[8] := '$00';
	            #EmptyData.TelegrammKennung[9] := '$00';
	            #EmptyData.TelegrammKennung[10] := '$00';
	            "SS_Port1_SendDaten".Port1 := #EmptyData;
	            
	            #nStateSend := 0;
	            
	        999: //ERROR TODO
	            #EmptyData.TelegrammKennung[1] := '$00';
	            #EmptyData.TelegrammKennung[2] := '$00';
	            #EmptyData.TelegrammKennung[3] := '$00';
	            #EmptyData.TelegrammKennung[4] := '$00';
	            #EmptyData.TelegrammKennung[5] := '$00';
	            #EmptyData.TelegrammKennung[6] := '$00';
	            #EmptyData.TelegrammKennung[7] := '$00';
	            #EmptyData.TelegrammKennung[8] := '$00';
	            #EmptyData.TelegrammKennung[9] := '$00';
	            #EmptyData.TelegrammKennung[10] := '$00';
	            
	            "SS_Port1_SendDaten".Port1 := #EmptyData;
	            #nStateSend := 0;
	            
	    END_CASE;
	    
	END_REGION
	
	REGION Empfangsfach verwalten / Telegramme erhalten
	    CASE #nStateReceive OF
	        #c0000_WaitingReceive:
	            REGION c0000: Waiting
	                //New Telegram
	                IF #fbTeleHandler.xOutTelegramAvailable THEN
	                    #fbTeleHandler.xInGetFirst := TRUE;
	                    #nStateReceive := #c0100_GetNewTelegram;
	                END_IF;
	            END_REGION
	        #c0100_GetNewTelegram:
	            REGION c0100: Get new telegram
	                #stNewTelegram := #fbTeleHandler.stOutNewTelegram;
	                #fbTeleHandler.xInGetFirst := FALSE;
	                
	                IF "SS_Port1_EmpfangsDaten".Port1.TelegrammKennung[1] = '$00' THEN // Warte bis Empfangsbereich frei ist
	                    #nStateReceive := #c0200_AnalyzeTelegram;
	                END_IF;
	            END_REGION
	        #c0200_AnalyzeTelegram:
	            REGION c0200: Analyze telegram
	                
	                IF #stNewTelegram.arDataString[3] = 'BReqM' THEN
	                    "FC_Send_ACK"(sInSeqNum := #stNewTelegram.arDataString[2], //Sequenznummer zurückgeben
	                                  FIFO := "DB_LGF_FIFO_CommWES_ASRS",
	                                  BUFFER := "DB_Buffer_CommunicationWES_ASRS".BUFFER);
	                END_IF;
	                
	                IF #stNewTelegram.arDataString[3] = 'BReqM' THEN
	                    "SS_Port1_EmpfangsDaten".Port1.TelegrammKennung[1] := 'B';
	                    "SS_Port1_EmpfangsDaten".Port1.TelegrammKennung[2] := 'R';
	                    "SS_Port1_EmpfangsDaten".Port1.TelegrammKennung[3] := 'e';
	                    "SS_Port1_EmpfangsDaten".Port1.TelegrammKennung[4] := 'q';
	                    "SS_Port1_EmpfangsDaten".Port1.TelegrammKennung[5] := 'M';
	                    
	                    "SS_Port1_EmpfangsDaten".Port1.TrolleyID := STRING_TO_DINT(#stNewTelegram.arDataString[4]); //Barcode vom LTA
	                    "SS_Port1_EmpfangsDaten".Port1.StoreGroup := STRING_TO_DINT(#stNewTelegram.arDataString[5]); // StoreGroup zu dem der Trolley gehört (KLÄREN!)
	                    "SS_Port1_EmpfangsDaten".Port1.Puffer_LinienNr := STRING_TO_INT(#stNewTelegram.arDataString[6]); // Pufferlinie 
	                    "SS_Port1_EmpfangsDaten".Port1.Aktion_1 := STRING_TO_INT(#stNewTelegram.arDataString[7]); //Reason Code
	                    
	                    #nStateReceive := #c0000_WaitingReceive;
	                ELSE //Unknown todo
	                    #nStateReceive := #c0000_WaitingReceive;
	                END_IF;
	            END_REGION
	
	            
	    END_CASE;
	END_REGION
END_FUNCTION_BLOCK

