FUNCTION_BLOCK "FB_CommunicationWCSBL"
{ 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";
      nState : Int;
      nStateSend : Int;
      xRetVal : Bool;
      stNewTelegram { S7_SetPoint := 'False'} : "UDT_TelegramData";
      stTeleGOHDRespM : "UDT_Telegram_GOHDRespM";
      arPayloadHelp : Array[0..200] of Byte;
      cnt : UInt;
      LStream_JsonDeserializer_Instance : "LStream_JsonDeserializer";
      typeElement { S7_SetPoint := 'False'} : Array[0..10] of "LStream_typeElement" := [(2, 'DecisionPoint', (), (), ()), (3, 'GIN', (), (), ()), (2, 'Barcode', (), (), ()), (1, 'Actions', (), (), true), ((), (), (), (), ()), ((), (), (), (), ()), ((), (), (), (), ()), ((), (), (), (), ()), ((), (), (), (), ()), ((), (), (), (), ()), ((), (), (), (), ())];
      xDone : Bool;
      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 
      xStart : Bool;
      test : "UDT_TelegramData_Send";
      EmptyData : "UDatenSend" := ([10('$00')], (), (), (), (), (), [()], [()]);
      arLaneStatus : Array[0..4] of String;   // Entnahmepuffer
      arLaneNix : Array[0..4] of String;
      empty : "UDT_TelegramData_Send";
      xSuccess : Bool;
      stLogTelegram : "UDT_TelegramData_Send";
      i : Int;
      nAction : Int;
   END_VAR


BEGIN
	REGION Info
	    // Kommunikation zu Fortna WCSBL 
	    // Telegramme:
	    // Senden:
	    // GOHDReqM  (Zielanfrage)             | Von Schönenberger -> Fortna WCSBL
	    // GOHDUM    (Update)                  | Von Schönenberger -> Fortna WCSBL 
	    // Empfangen:
	    // GOHDRespM (Antwort auf Zielanfrage) | Von Fortna WCSBL  -> Schönenberger
	END_REGION
	
	// Fortna WCSBL
	// IP: 172.22.160.23
	// Port: 30650
	
	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 := 70;
	    //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 := 30650;
	    //partner port number, use only in case of client or specified partner (possible values: 1...49151; recommended values: 2000...5000)
	    #fbTeleHandler.stInTcpTypeConfig.connection.partnerPort := 30650;
	    
	    //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] := 23;
	    
	    #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".nSeqNumWCSBL := 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:= 1,
	                         FIFO := "DB_LGF_FIFO_CommWCSBL",
	                         BUFFER := "DB_Buffer_CommunicationWCSBL".BUFFER,
	                         nInOutSequenceNumber := "DB_CommunicationParameters".nSeqNumWCSBL);
	        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_Port2_SendDaten".Port2.TelegrammKennung[1] <> '$00' THEN
	                #nStateSend := 100;
	            END_IF;
	            
	        100: //Neues Telegramm
	            Chars_TO_Strg(Chars := "SS_Port2_SendDaten".Port2.TelegrammKennung,
	                          pChars := 0,
	                          Cnt := 0,
	                          Strg => #sTelegramKennung);
	            
	            //MB3143 -> GOH.OBBuffer.01 (StoreGroup)
	            //MB3121 -> GOH.OBBuffer.02 (StoreGroup)
	            //MB3123 -> GOH.OBBuffer.03 (StoreGroup)
	            //MB4503 -> GOH.Ship.01 (LaneStatus)
	            
	            IF #sTelegramKennung = 'GOHDReqM' THEN
	                
	                IF "SS_Port2_SendDaten".Port2.StationsNr = 4503 THEN //GOH.Ship.01
	                    
	                    #arLaneStatus[0] := "FC_Get_LaneStatus_Omni"("SS_Port2_SendDaten".Port2.Status_2[0]); //Linie 1
	                    #arLaneStatus[1] := "FC_Get_LaneStatus_Omni"("SS_Port2_SendDaten".Port2.Status_2[1]); //Linie 2
	                    #arLaneStatus[2] := "FC_Get_LaneStatus_Omni"("SS_Port2_SendDaten".Port2.Status_2[2]); //Linie 3
	                    #arLaneStatus[3] := "FC_Get_LaneStatus_Omni"("SS_Port2_SendDaten".Port2.Status_2[4]); //Linie 4
	                    
	                    "FC_Send_GOHDReqM"(sInPLCID := "cPLCID",
	                                       xInSSCCReq := FALSE,
	                                       xInLengthReq := FALSE,
	                                       xInDockDoorReq := FALSE,
	                                       xInLaneStatusReq := TRUE,
	                                       nInBarcode := "SS_Port2_SendDaten".Port2.TrolleyID,
	                                       sInSSCC := '',
	                                       sInDecisionPoint := "FC_Convert_SchleusetoDecisionPoint"("SS_Port2_SendDaten".Port2.StationsNr),
	                                       sInDockDoor := '',
	                                       sInLengthInfo := '',
	                                       arInLaneStatus := #arLaneStatus,
	                                       nInLaneCnt := 4, //für GOH.Ship.01 (Entnahmepuffer 4 Linien)
	                                       FIFO := "DB_LGF_FIFO_CommWCSBL",
	                                       BUFFER := "DB_Buffer_CommunicationWCSBL".BUFFER,
	                                       nInOutSequenceNumber := "DB_CommunicationParameters".nSeqNumWCSBL);
	                    
	                    #nStateSend := 300;
	                    
	                ELSIF ("SS_Port2_SendDaten".Port2.StationsNr = 3143) OR ("SS_Port2_SendDaten".Port2.StationsNr = 3121) OR ("SS_Port2_SendDaten".Port2.StationsNr = 3123) THEN
	                    "FC_Send_GOHDReqM"(sInPLCID := "cPLCID",
	                                       xInSSCCReq := FALSE,
	                                       xInLengthReq := FALSE,
	                                       xInDockDoorReq := FALSE,
	                                       xInLaneStatusReq := FALSE,
	                                       nInBarcode := "SS_Port2_SendDaten".Port2.TrolleyID,
	                                       sInSSCC := '',
	                                       sInDecisionPoint := "FC_Convert_SchleusetoDecisionPoint"("SS_Port2_SendDaten".Port2.StationsNr),
	                                       sInDockDoor := '',
	                                       sInLengthInfo := '',
	                                       arInLaneStatus := #arLaneNix,
	                                       nInLaneCnt := 0,
	                                       FIFO := "DB_LGF_FIFO_CommWCSBL",
	                                       BUFFER := "DB_Buffer_CommunicationWCSBL".BUFFER,
	                                       nInOutSequenceNumber := "DB_CommunicationParameters".nSeqNumWCSBL);
	                    
	                    #nStateSend := 300;
	                    
	                ELSE
	                    #nStateSend := 999;
	                    
	                END_IF;
	                
	            ELSIF #sTelegramKennung = 'GOHDUM' THEN
	                "FC_Send_GOHDUM"(sInPLCID := "cPLCID",
	                                 nInBarcode := "SS_Port2_SendDaten".Port2.TrolleyID,
	                                 sInDecisionPoint := "FC_Convert_SchleusetoDecisionPoint"("SS_Port2_SendDaten".Port2.StationsNr),
	                                 sInActionTaken := "FC_ActionConvert"("SS_Port2_SendDaten".Port2.Puffer_LinienNr), //DELETE(IN := INT_TO_STRING("SS_Port2_SendDaten".Port2.Status_1), L := 1, P := 1),
	                                 nReasonCode := '1', //todo
	                                 FIFO := "DB_LGF_FIFO_CommWCSBL",
	                                 BUFFER := "DB_Buffer_CommunicationWCSBL".BUFFER,
	                                 nInOutSequenceNumber := "DB_CommunicationParameters".nSeqNumWCSBL);
	                
	                #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_Port2_SendDaten".Port2 := #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_Port2_SendDaten".Port2 := #EmptyData;
	            #nStateSend := 0;
	            
	    END_CASE;
	    
	END_REGION
	
	REGION Empfangen
	    CASE #nState OF
	        0: // Waiting
	            //New Telegram
	            IF #fbTeleHandler.xOutTelegramAvailable THEN
	                #fbTeleHandler.xInGetFirst := TRUE;
	                #nState := 100;
	            END_IF;
	        100: // Get new Telegram
	            #stNewTelegram := #fbTeleHandler.stOutNewTelegram;
	            #fbTeleHandler.xInGetFirst := FALSE;
	            
	            IF "SS_Port1_EmpfangsDaten".Port1.TelegrammKennung[1] = '$00' THEN // Warte bis Empfangsbereich frei ist
	                #stLogTelegram.nDataCount := #stNewTelegram.nDataCount;
	                
	                FOR #i := 1 TO 12 DO
	                    #stLogTelegram.arDataString[#i] := #stNewTelegram.arDataString[#i];
	                END_FOR;
	                
	                REGION LOG
	                    IF "FB_CommunicationLogger_DB".fbTeleHandler.xOutConnectionActive THEN
	                        "FC_FIFO_Append"(DataIn := #stLogTelegram,
	                                         InitialItem := #empty,
	                                         MaxNo := 100,
	                                         Success => #xSuccess,
	                                         fifoBuffer := "DB_LGF_FIFO_CommLogger",
	                                         buffer := "DB_Buffer_CommunicationLogger".BUFFER);
	                    END_IF;
	                    
	                END_REGION
	                
	                
	                #nState := 200;
	            END_IF;
	            
	        200: //Analyze Telegram
	            #stTeleGOHDRespM.stHeader.sPlcId := #stNewTelegram.arDataString[1];
	            #stTeleGOHDRespM.stHeader.sSeqNum := #stNewTelegram.arDataString[2];
	            #stTeleGOHDRespM.stHeader.sMessageType := #stNewTelegram.arDataString[3];
	            
	            // "FC_Send_ACK"(sInSeqNum := #stNewTelegram.arDataString[2], //Sequenznummer zurückgeben
	            //               FIFO := "DB_LGF_FIFO_CommWCSBL",
	            //               BUFFER := "DB_Buffer_CommunicationWCSBL".BUFFER);
	            
	            IF #stTeleGOHDRespM.stHeader.sMessageType = 'GOHDRespM' THEN
	                
	                Strg_TO_Chars(Strg := #stNewTelegram.arDataString[4],
	                              pChars := 0,
	                              Cnt => #cnt,
	                              Chars := #arPayloadHelp);
	                
	                #typeElement[0].type := 2;
	                #typeElement[0].key := 'DecisionPoint';
	                #typeElement[1].type := 3;
	                #typeElement[1].key := 'GIN';
	                #typeElement[2].type := 2;
	                #typeElement[2].key := 'Barcode';
	                #typeElement[3].type := 1;
	                #typeElement[3].key := 'Actions';
	                #typeElement[9].type := 1;//2;
	                #typeElement[9].key := 'StoreGroup';
	                #xStart := TRUE;
	                
	                IF #xDone THEN
	                    #xStart := FALSE;
	                    
	                    
	                    //Für Andi
	                    //Message Type
	                    "SS_Port2_EmpfangsDaten".Port2.TelegrammKennung[1] := 'G';
	                    "SS_Port2_EmpfangsDaten".Port2.TelegrammKennung[2] := 'O';
	                    "SS_Port2_EmpfangsDaten".Port2.TelegrammKennung[3] := 'H';
	                    "SS_Port2_EmpfangsDaten".Port2.TelegrammKennung[4] := 'D';
	                    "SS_Port2_EmpfangsDaten".Port2.TelegrammKennung[5] := 'R';
	                    "SS_Port2_EmpfangsDaten".Port2.TelegrammKennung[6] := 'e';
	                    "SS_Port2_EmpfangsDaten".Port2.TelegrammKennung[7] := 's';
	                    "SS_Port2_EmpfangsDaten".Port2.TelegrammKennung[8] := 'p';
	                    "SS_Port2_EmpfangsDaten".Port2.TelegrammKennung[9] := 'M';
	                    
	                    STRG_VAL(IN := #typeElement[4].value,
	                             FORMAT := 0,
	                             P := 1,
	                             OUT => #nAction);
	                    
	                    //DecisionPoint und Aktion
	                    IF (#typeElement[0].value) = ('GOH.OBBuffer.01') THEN
	                        "SS_Port2_EmpfangsDaten".Port2.StationsNr := 3143;
	                        
	                        IF #nAction = -1 THEN
	                            "SS_Port2_EmpfangsDaten".Port2.Puffer_LinienNr := 3127;
	                        ELSIF #nAction = 1 THEN
	                            "SS_Port2_EmpfangsDaten".Port2.Puffer_LinienNr := 3130;
	                        ELSE
	                            "SS_Port2_EmpfangsDaten".Port2.Puffer_LinienNr := 3130;
	                        END_IF;
	                        
	                    ELSIF (#typeElement[0].value) = ('GOH.OBBuffer.02') THEN
	                        "SS_Port2_EmpfangsDaten".Port2.StationsNr := 3121;
	                        
	                        IF #nAction = -1 THEN
	                            "SS_Port2_EmpfangsDaten".Port2.Puffer_LinienNr := 3120;
	                        END_IF;
	                        
	                    ELSIF (#typeElement[0].value) = ('GOH.OBBuffer.03') THEN
	                        "SS_Port2_EmpfangsDaten".Port2.StationsNr := 3123;
	                        
	                        IF #nAction = -1 THEN
	                            "SS_Port2_EmpfangsDaten".Port2.Puffer_LinienNr := 3120;
	                        END_IF;
	                        
	                    ELSIF (#typeElement[0].value) = ('GOH.Ship.01') THEN
	                        "SS_Port2_EmpfangsDaten".Port2.StationsNr := 4503;
	                        
	                        "SS_Port2_EmpfangsDaten".Port2.Puffer_LinienNr := #nAction;
	                        
	                    END_IF;
	                    
	                    STRG_VAL(IN := #typeElement[1].value,
	                             FORMAT := 0,
	                             P := 1,
	                             OUT => #stTeleGOHDRespM.stPayload.nGin);
	                    
	                    STRG_VAL(IN := #typeElement[2].value,
	                             FORMAT := 0,
	                             P := 1,
	                             OUT => "SS_Port2_EmpfangsDaten".Port2.TrolleyID);
	                    
	                    // STRG_VAL(IN := #typeElement[4].value,
	                    //          FORMAT := 0,
	                    //          P := 1,
	                    //          OUT => #nAction);
	                    
	                    STRG_VAL(IN := #typeElement[6].value,//#typeElement[10].value,
	                             FORMAT := 0,
	                             P := 1,
	                             OUT => "SS_Port2_EmpfangsDaten".Port2.StoreGroup);
	                    
	                    
	                    
	                    // #stTeleGOHDRespM.stPayload.arActions[0] := #typeElement[4].value;
	                    // #stTeleGOHDRespM.stPayload.arActions[1] := #typeElement[5].value;
	                    // #stTeleGOHDRespM.stPayload.arActions[2] := #typeElement[6].value;
	                    // #stTeleGOHDRespM.stPayload.arActions[3] := #typeElement[7].value;
	                    // #stTeleGOHDRespM.stPayload.arActions[4] := #typeElement[8].value;
	                    
	                   
	                    #xDone := FALSE;
	                    
	                    
	                 //   #stTeleGOHDRespM.stPayload.sTimeStamp := #typeElement[9].value;
	                    
	                    (*    REGION Send ACK
	                            "FC_TeleClear"(#stTelegramToSend);
	                            
	                            #xRetVal := "FC_TeleSetData"(nDataField := 1,
	                                                         sData := '4711',
	                                                         stInOutTelegram := #stTelegramToSend);
	                            
	                            #xRetVal := "FC_TeleSetData"(nDataField := 2,
	                                                         sData := #stNewTelegram.arDataString[2],
	                                                         stInOutTelegram := #stTelegramToSend);
	                            
	                            #xRetVal := "FC_TeleSetData"(nDataField := 3,
	                                                         sData := 'ACK',
	                                                         stInOutTelegram := #stTelegramToSend);
	                            
	                            #xRetVal := "FC_TeleSetData"(nDataField := 4,
	                                                         sData := '123',
	                                                         stInOutTelegram := #stTelegramToSend);
	                            #xSendTele := TRUE;
	                        END_REGION *)
	                    
	                    #nState := 0;
	                END_IF;
	            ELSE
	                #nState := 0;
	            END_IF;
	    END_CASE;
	END_REGION
	#LStream_JsonDeserializer_Instance(execute := #xStart,
	                                   tree := #typeElement,
	                                   raw := #arPayloadHelp);
	
	IF #LStream_JsonDeserializer_Instance.done THEN
	    #xDone := TRUE;
	END_IF;
	
END_FUNCTION_BLOCK

