FUNCTION_BLOCK "FB_StationUnloadPin"
{ S7_Optimized_Access := 'TRUE' }
VERSION : 0.1
   VAR_INPUT 
      xInStartUnloading : Bool;
      xInStopUnloading : Bool;
      xInNextHanger : Bool;
      xInBefore : Bool;
      stInPartAfterSwitch : "UDT_Sensor";
      nInBarcode : DInt;
      sInBarcode : String;
      xInReRouteAllowed : Bool := TRUE;
      xInUnloadingCheckSensor : Bool;
      xInMonitorUnloading : Bool;
      xInQuitLocal : Bool;
      xInBypass : Bool;
   END_VAR

   VAR_OUTPUT 
      xOutUnloadingDone : Bool;
      nOutBarcode : DInt;
      sOutBarcode : String;
      xOutSwitch : Bool;
      xOutLineOverloaded : Bool;
      xOutLineOverloadAhead : Bool;
      wOutErrorWord : Word;
      xOutLineOverloadedHigh : Bool;
      xOutLineOverloadedLow : Bool;
      xOutUnloadingFail : Bool;
      xOutUnloadingError : Bool;
   END_VAR

   VAR_IN_OUT 
      stInOutControlUnitCabinet : "UDT_MainState";
      stInOutConveyorStations : "stConveyorStations";
      arInOutCarrier : Array[*] of "stCarrier";
      nNoReadCounter : UDInt;
      stInOutHMI : "UDT_HMI_UnloadingStation";
   END_VAR

   VAR 
      nState : Int := -10;
      TOnLineFullTimer {InstructionName := 'TON_TIME'; LibVersion := '1.0'} : TON_TIME;
      tOnUnloadingCheck {InstructionName := 'TON_TIME'; LibVersion := '1.0'} : TON_TIME;
   END_VAR
   VAR RETAIN
      CountSwitch {InstructionName := 'CTU_UDINT'; LibVersion := '1.0'} : CTU_UDINT;
      nCount : UDInt;
   END_VAR
   VAR 
      rTrigSwitch {InstructionName := 'R_TRIG'; LibVersion := '1.0'} : R_TRIG;
      rTrigUnload {InstructionName := 'R_TRIG'; LibVersion := '1.0'} : R_TRIG;
      tUnloadingCheckTime : Time := T#5s;
      xUnloadingCheck : Bool;
      tLineFullTime : Time := T#3s;
      tOnStateTimer {InstructionName := 'TON_TIME'; LibVersion := '1.0'} : TON_TIME;
      xStateTimer : Bool;
      tStateTimer : Time;
      xFlgTrolleySensor : Bool;
      xFlgStartUnloading : Bool;
      fbMonitoringLineOverload : "FB_Monitoring";
      fbMonitoringUnloadError : "FB_Monitoring";
      xEdgeStoreLineOverload : Bool;
      stHangerStatus { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Struct
         xOnline { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Bool;
         nTarget { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Int;
         xDoubleHangerOkay { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Bool;
         xTargetDoubleHanger { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Bool;
         xNoRead { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Bool;
         xPartMissing { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Bool;
         xTargetSetByMFS { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Bool;
         xReportedToMFS { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Bool;
         xReRouteOverflow { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Bool;
         xReRouteBalancing { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Bool;
         xReRouteUnavailable { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Bool;
      END_STRUCT;
   END_VAR

   VAR_TEMP 
      t_status : Bool;
      tmpSuccess : Bool;
   END_VAR


BEGIN
	REGION xOutLineOverloaded Stau
	    IF #TOnLineFullTimer.Q THEN
	        //OR
	        //#tOnUnloadingCheck.Q THEN
	        #xFlgTrolleySensor := TRUE;
	        #xOutLineOverloaded := 1;
	    ELSE
	        #xFlgTrolleySensor := FALSE;
	        #xOutLineOverloaded := 0;
	    END_IF;
	    
	    // Detect change of Line Overload
	    #xOutLineOverloadedHigh := #TOnLineFullTimer.Q AND NOT #xEdgeStoreLineOverload;
	    
	    #xOutLineOverloadedLow := NOT #TOnLineFullTimer.Q AND #xEdgeStoreLineOverload;
	    
	    #xEdgeStoreLineOverload := #TOnLineFullTimer.Q;
	    
	END_REGION
	
	IF #xInStartUnloading AND #xFlgTrolleySensor AND #xInReRouteAllowed THEN
	    #xOutUnloadingFail := TRUE;
	    #nOutBarcode := #nInBarcode;
	    #sOutBarcode := #sInBarcode;
	    "FC_SHR_TargetSet_ReRoutePin"(nInBarcodeNo := #nInBarcode,
	                               nInTarget := INT_TO_USINT(#stInOutConveyorStations.stData.nStations),
	                               xOutSuccess => #tmpSuccess,
	                               stInOutConveyorStations := #stInOutConveyorStations);
	ELSE
	    #xOutUnloadingFail := FALSE;
	END_IF;
	
	#rTrigUnload(CLK:=#xInStartUnloading);
	
	REGION Schrittkette
	    CASE #nState OF
	        -10:    // Init
	            #xOutSwitch := 0;
	            #xStateTimer := 0;
	            #xOutUnloadingDone := 0;
	            #nState := 0;
	            
	        0:      // Standby
	            #xOutUnloadingDone := 0;
	            
	            // IF #tOnStateTimer.Q (* #xFlgTrolleySensor *)THEN // Wenn Weiche voll //VON MYTHERESA -> STÖRT HIER, TEST
	            //     #xUnloadingCheck := FALSE; // nicht möglich, da Flankenauswertung, bei dauerbelegtem Sensor sinnfrei
	            //     #xOutSwitch := 0; // Switch schliessen
	            // END_IF;
	            
	            IF #rTrigUnload.Q (* AND NOT #tOnStateTimer.Q *)THEN //VON MYTHERESA -> STÖRT HIER, TEST
	                #xOutSwitch := 1;
	                #nOutBarcode := #nInBarcode;
	                #sOutBarcode := #sInBarcode;
	                IF #xInMonitorUnloading THEN
	                    #xUnloadingCheck := 1;
	                END_IF;
	                "FC_SHR_ExtractedHangerPin"(xInUnloadingDone := TRUE,
	                                            nInBarcode := #nOutBarcode,
	                                            xInBypass:= #xInBypass,
	                                            stInOutConveyorStations := #stInOutConveyorStations,
	                                            arInOutCarrier:= #arInOutCarrier);
	                #xOutUnloadingDone := 1;
	            ELSIF #xInStopUnloading THEN
	                #xOutSwitch := 0;
	            END_IF;
	            
	        1100:   //  Warten bis fertig mit Switch offen lassen     
	            #xOutSwitch := 1;
	            IF NOT #xInStartUnloading THEN
	                #nState := 1110;        // Switch offen lassen
	            END_IF;
	            
	        1110: // Switch offen lassen
	            #xOutSwitch := 1;
	            #xOutUnloadingDone := 1;
	            #nState := 0;
	        1200:   //  Warten bis fertig mit Switch offen lassen     
	            #xOutSwitch := 1;
	            IF NOT #xInStartUnloading THEN
	                "FC_SHR_ExtractedHangerPin"(xInUnloadingDone := NOT #xInStartUnloading,
	                                            nInBarcode := #nOutBarcode,
	                                            xInBypass:=#xInBypass,
	                                            stInOutConveyorStations := #stInOutConveyorStations,
	                                            arInOutCarrier:= #arInOutCarrier);
	                #nState := 1210;        // Switch offen lassen
	            END_IF;
	        1210: // Switch schließen
	            #xOutSwitch := 0;
	            #xOutUnloadingDone := 1;
	            #nState := 0;
	        1300: //Switch vorher öffnen
	            #xOutSwitch := 1;
	            #nState := 0;
	    END_CASE;
	END_REGION
	REGION Counter
	    #rTrigSwitch(CLK := #xOutSwitch);
	    #CountSwitch(CU := #rTrigSwitch.Q,
	                 PV := 1,
	                 CV => #nCount);
	END_REGION ;
	REGION Timer    
	    #tOnStateTimer(IN := #xFlgTrolleySensor,//xStateTimer,
	                   PT := T#800ms);//#tStateTimer);
	    
	    #TOnLineFullTimer(IN := #stInPartAfterSwitch.xDbncdSensor,
	                      PT := #tLineFullTime);
	    
	    IF #xInUnloadingCheckSensor AND // Sensor nach Weiche
	        #xUnloadingCheck AND // Monitoring aktiviert
	        NOT #tOnUnloadingCheck.Q  // Monitoring nicht bereits ausgeschlagen
	    THEN
	        #xUnloadingCheck := FALSE;
	    END_IF;
	    
	    IF #tOnUnloadingCheck.Q AND  // Monitoring ausgeschlagen?
	        (#stInOutControlUnitCabinet.xQuitError OR #xInQuitLocal) // dann am Schaltschrank zu quittieren
	    THEN
	        #xUnloadingCheck := FALSE; // Monitoring Ende
	    END_IF;
	    
	    // Timer bis Teil am Sensor vorbei muss
	    #tOnUnloadingCheck(IN := #xUnloadingCheck AND #stInOutControlUnitCabinet.xRunning,
	                       PT := #tUnloadingCheckTime);
	    
	    #xOutUnloadingError := #tOnUnloadingCheck.Q;
	    
	END_REGION
	
	REGION Flanken
	    
	    #xFlgStartUnloading := #xInStartUnloading;
	    
	END_REGION
	
	REGION Monitoring
	    
	    #fbMonitoringLineOverload.stSettings.nErrorType := 1;
	    #fbMonitoringLineOverload.stSettings.xErrLedIfMachineIsOff := TRUE;
	    #fbMonitoringLineOverload.stSettings.xSelfQuit := TRUE;
	    #fbMonitoringLineOverload(sInFctnName := #stInOutHMI.sName,
	                              wInTextListId_Function := 500,
	                              wInTextListId_Message := 500,
	                              sInSuffix := #stInPartAfterSwitch.sName,
	                              InOutMachineState := #stInOutControlUnitCabinet,
	                              xInQuitError := #stInOutControlUnitCabinet.xQuitError OR #xInQuitLocal,
	                              xInSignal := NOT #TOnLineFullTimer.Q,
	                              sInAlarmMessage := 'Die Linie ist voll');
	    
	    #fbMonitoringUnloadError.stSettings.nErrorType := 1;
	    #fbMonitoringUnloadError.stSettings.xErrLedIfMachineIsOff := TRUE;
	    #fbMonitoringUnloadError.stSettings.xSelfQuit := TRUE;
	    #fbMonitoringUnloadError(sInFctnName := #stInOutHMI.sName,
	                             wInTextListId_Function := 500,
	                             wInTextListId_Message := 501,
	                             sInSuffix := #stInPartAfterSwitch.sName,
	                             InOutMachineState := #stInOutControlUnitCabinet,
	                             xInQuitError := #stInOutControlUnitCabinet.xQuitError OR #xInQuitLocal,
	                             xInSignal := NOT #xOutUnloadingError,
	                             sInAlarmMessage := 'Laufzeitfehler bei Weiche/Abwurf');
	    
	END_REGION
	
	REGION Visu
	    REGION Status
	        IF NOT #xOutUnloadingError AND (NOT #wOutErrorWord > 0) THEN
	            IF #stInOutHMI.xEnableControl THEN
	                #stInOutHMI.bStatus := 3;
	            ELSE
	                CASE #nState OF
	                    -10:
	                        #stInOutHMI.bStatus := 0; // NOT_AVAILABLE
	                    0, 1100, 1110, 1200, 1210, 1300:
	                        #stInOutHMI.bStatus := 1; // AVAILABLE
	                    ELSE  //Fallback
	                        #stInOutHMI.bStatus := 0; // NOT AVAILABLE
	                END_CASE;
	            END_IF;
	        ELSE // Fehler
	            #stInOutHMI.bStatus := 2; // ERROR
	        END_IF;
	    END_REGION
	    
	    REGION Modes
	        // Int16 Bit-codiert
	        #stInOutHMI.nMode.%X0 := (#nState = -10); // The device is turned off
	        #stInOutHMI.nMode.%X1 := (#nState = 0) OR (#nState = 1100) OR (#nState = 1110) OR (#nState = 1200) OR (#nState = 1210) OR (#nState = 1300); // The device is turned on
	        #stInOutHMI.nMode.%X2 := #stInOutHMI.xEnableControl; //Hand
	        #stInOutHMI.nMode.%X3 := FALSE; //NIU
	        #stInOutHMI.nMode.%X10 := #xOutUnloadingError; // Timeout Error
	    END_REGION
	    
	    // Idee: Schrittkette setzt im Normalfall den Switch.
	    // Wenn EnableControl TRUE ist, dann wird der Ausgang hier einfach überschrieben mit dem HMI-Wert
	    REGION Handbetrieb
	        IF #stInOutHMI.xEnableControl THEN
	            #xOutSwitch := #stInOutHMI.xSetSwitch;
	        ELSE
	            #stInOutHMI.xSetSwitch := #xOutSwitch;
	        END_IF;
	        
	        #stInOutHMI.xInHome := NOT #xOutSwitch;
	        #stInOutHMI.xInWork := #xOutSwitch;
	        
	    END_REGION
	    
	    #stInOutHMI.xLineFull := #TOnLineFullTimer.Q;
	END_REGION
END_FUNCTION_BLOCK

