FUNCTION_BLOCK "FB_StateMain"
{ S7_Optimized_Access := 'TRUE' }
VERSION : 0.1
   VAR_INPUT 
      xInBtnMachineOn : Bool;   // Anlage Ein
      xInBtnMachineNotOff : Bool;   // Anlage Aus
      xInBtnLightTest : Bool;   // Lampentest
      xInBtnTrigMot : Bool;   // Trig Mot
      xInBtnQuitError : Bool;   // Start nach Störung
      xInAllReadyToStart : Bool;   // Alles bereit
      xInAllInExecute : Bool;   // Alle Antriebe in Run
      xInAllStarted : Bool;   // Starten erfolgreich beendet
      xInSafetyActive : Bool;   // Safety aktiv
      xInAllInSafeState : Bool;   // Alles im sicheren Status
      stSettings : Struct   // Einstellungen
         tCancelStarting : Time := t#10s;
         xEnableStartUpWarning : Bool;
         xPressMachineOnAllTime : Bool;
         tStartUpTime : Time := T#3s;
      END_STRUCT;
   END_VAR

   VAR_IN_OUT 
      stInOutControlUnitCabinet : "UDT_MainState";   // Schnittstelle MainState
      stInOutHMI : "UDT_HMI_StateMachine";   // NUR FÜR HMI
   END_VAR

   VAR 
      nState : Int := -10;   // Schritt
      sStateText : String;   // Schritttext
      tOnStartUpTimer {InstructionName := 'TON_TIME'; LibVersion := '1.0'} : TON_TIME;   // Anlaufverzögerung
      nConveyorStartUpCounter : Int;   // Counter Förderer
      xQuitErrorFlag : Bool;   // Start nach Störung Flag
      stControl : Struct   // Start,Stop,Quit
         xStart : Bool;
         xStop : Bool;
         xQuitt : Bool;
      END_STRUCT;
   END_VAR

   VAR_TEMP 
      nCounter : Int;
      nNoStartingAct : Int;
   END_VAR


BEGIN
	REGION MainStateMachine
	    CASE #nState OF
	     
	        "E_DeviceState.eUndefined":
	            REGION Undefined
	                #sStateText := 'StartUp';
	                #nState := "E_DeviceState.eStopped";
	            END_REGION ;
	            
	        "E_DeviceState.eStopped":
	            REGION Stopped
	                #sStateText := 'Stopped';
	                
	                IF #xInAllReadyToStart AND NOT #stInOutControlUnitCabinet.xStopMachine THEN
	                    #nState := "E_DeviceState.eIdle";
	                END_IF;
	                #stInOutControlUnitCabinet.xStopMachine := FALSE;
	            END_REGION ;   
	            
	        "E_DeviceState.eIdle":
	            
	            REGION IDLE
	                #sStateText := 'Idle';
	                IF NOT #xInAllReadyToStart OR #stInOutControlUnitCabinet.xStopMachine THEN
	                    #nState := "E_DeviceState.eStopped";
	                ELSIF (#xInBtnMachineOn OR #stInOutHMI.xStart OR #stControl.xStart)AND (((#xInBtnMachineNotOff AND NOT #stControl.xStop AND NOT #stInOutHMI.xStop) AND NOT #stControl.xStop AND NOT #stInOutHMI.xStop) AND NOT #stControl.xStop AND NOT #stInOutHMI.xStop) THEN
	                    #nState := "E_DeviceState.eStarting";
	                    #stControl.xStart := FALSE;
	                END_IF;
	            END_REGION ;   
	            
	        "E_DeviceState.eStarting":
	            REGION Starting
	                #sStateText := 'Start UP Warning Time';
	                IF NOT #xInAllReadyToStart OR #stInOutControlUnitCabinet.xStopMachine THEN
	                    #nState := "E_DeviceState.eStopped";
	                ELSIF #xInAllStarted AND
	                    (NOT #stSettings.xEnableStartUpWarning OR
	                    (#stSettings.xEnableStartUpWarning AND #tOnStartUpTimer.Q)) THEN
	                    #nState := 120;
	                ELSIF (NOT #xInBtnMachineOn AND #stSettings.xPressMachineOnAllTime)
	                    OR NOT #xInBtnMachineNotOff OR
	                    #tOnStartUpTimer.ET > #stSettings.tCancelStarting
	                THEN
	                    #nState := "E_DeviceState.eStopping";
	                END_IF;
	            END_REGION ;
	  
	        120:
	            REGION Waiting for All in Excecute
	                #sStateText := 'Waiting for All in Execute';
	                
	                IF #xInAllInExecute THEN
	                    #nState := "E_DeviceState.eExecute";
	                    #nConveyorStartUpCounter := 0;
	                ELSIF NOT ((#xInBtnMachineNotOff AND NOT #stControl.xStop AND NOT #stInOutHMI.xStop) AND NOT #stControl.xStop AND NOT #stInOutHMI.xStop) OR #stInOutControlUnitCabinet.xStopMachine THEN
	                    #nState := "E_DeviceState.eStopping";
	                END_IF;
	            END_REGION
	            
	        "E_DeviceState.eExecute":
	            
	            REGION Execute
	                #sStateText := 'Execute';
	                IF NOT #xInSafetyActive THEN
	                    #nState := "E_DeviceState.eHolding";
	                    #nConveyorStartUpCounter := 0;
	                ELSIF NOT (#xInBtnMachineNotOff AND NOT #stControl.xStop AND NOT #stInOutHMI.xStop) OR #stInOutControlUnitCabinet.xStopMachine THEN
	                    #nState := "E_DeviceState.eStopping";
	                ELSIF FALSE THEN
	                    #nState := "E_DeviceState.eSuspending";
	                END_IF;
	                IF #nConveyorStartUpCounter < 6000 THEN
	                    #nConveyorStartUpCounter := #nConveyorStartUpCounter + 1;
	                ELSIF #xInBtnTrigMot THEN
	                    #nConveyorStartUpCounter := 0;
	                END_IF;
	            END_REGION ;
	            
	        "E_DeviceState.eHolding":
	            
	            #sStateText := 'HOLDING: When the machine is in the EXECUTE state the Hold command can be used to start HOLDING logic which brings the machine to a controlled stop or to a state which represents HELD for the particular machine mode. ';
	            #nState := "E_DeviceState.eHeld";
	            
	        "E_DeviceState.eHeld":
	            
	            REGION Held
	                #sStateText := 'HELD: The HELD state would typically be used by the operator to hold the temporarily hold the machines operation whilst material blockages are cleared, or to stop throughput whilst a downstream problem is resolved.';
	                IF (NOT (#xInBtnMachineNotOff AND NOT #stInOutHMI.xStop)) OR #stInOutControlUnitCabinet.xStopMachine THEN
	                    #nState := "E_DeviceState.eStopping";
	                ELSIF #xInSafetyActive THEN
	                    #nState := "E_DeviceState.eUnholding";
	                END_IF;
	            END_REGION ;
	        "E_DeviceState.eUnholding":
	            
	            REGION Unholding
	                #sStateText := 'Un-Holding: The UNHOLDING state is typically a response to an operator command to resume EXECUTE state.  UNHOLDING prepares the machine to re-enter the EXECUTE state.';
	                IF NOT #stSettings.xEnableStartUpWarning OR
	                    (#stSettings.xEnableStartUpWarning AND #tOnStartUpTimer.Q) THEN
	                    #nState := "E_DeviceState.eExecute";
	                END_IF;
	            END_REGION
	
	            
	        "E_DeviceState.eSuspending":
	            
	            #sStateText := 'SUSPENDING: This state is a result of a command change from the EXECUTE state.  This state is typically required prior to the SUSPENDED wait state, and prepares the machine (ie stops glue cycles, stops carton feeds, etc) prior to the SUSPEND state.';
	            #nState := "E_DeviceState.eSuspended";
	        "E_DeviceState.eSuspended":
	            
	            REGION Suspended
	                #sStateText := 'SUSPENDED: The machine may be running at the relevant setpoint speed, there is no product being produced. This state can be reached as a result of a machine status, and differs from HELD in that HELD is typically a result of an operator request.';
	                IF NOT (#xInBtnMachineNotOff AND NOT #stControl.xStop AND NOT #stInOutHMI.xStop) OR #stInOutControlUnitCabinet.xStopMachine THEN
	                    #nState := "E_DeviceState.eStopping";
	                ELSIF TRUE THEN
	                    #nState := "E_DeviceState.eUnsuspending";
	                END_IF;
	            END_REGION ;
	            
	        "E_DeviceState.eUnsuspending":
	            
	            #sStateText := 'UN-SUSPENDING: This state is a result of a request from SUSPENDED state to go back to the EXECUTE state.  This actions of this state may include: ramping up speeds, turning on vaccums, the re-engagement of clutches.';
	            (*IF NOT #xInSafetyOk THEN
	                  #nState := "E_DeviceState.eHolding";
	              ELSE *)
	              #nState := "E_DeviceState.eExecute";
	(*            END_IF; *)
	              
	        "E_DeviceState.eStopping":
	            
	            REGION Stopping
	                #sStateText := 'Stopping';
	                #nState := 5010;
	            END_REGION
	        5010:
	            #sStateText := 'Waiting for Safe State';
	            
	            IF #xInAllInSafeState THEN
	                #nState := "E_DeviceState.eStopped";
	            END_IF;
	    END_CASE;
	END_REGION
	// 
	REGION Global stop conditions
	    IF (#nState > "E_DeviceState.eIdle") AND
	        (#nState < "E_DeviceState.eStopping") AND
	        NOT #xInAllReadyToStart THEN
	        #nState := "E_DeviceState.eStopped";
	    END_IF;
	END_REGION
	
	REGION Timer
	    #tOnStartUpTimer(IN := (#nState = "E_DeviceState.eStarting" OR #nState = "E_DeviceState.eUnholding"),
	                            PT := #stSettings.tStartUpTime);
	END_REGION
	
	REGION Outputs
	    #stInOutControlUnitCabinet.xStartUpWarning := (#nState = "E_DeviceState.eStarting" OR (#nState = "E_DeviceState.eUnholding" AND #stSettings.xEnableStartUpWarning)) AND #stSettings.xEnableStartUpWarning AND "Clock_1Hz";
	    #stInOutControlUnitCabinet.xStarting := (#nState = "E_DeviceState.eStarting") OR (#nState = "E_DeviceState.eUnholding");// AND #stSettings.xEnableStartUpWarning;
	    
	    #stInOutControlUnitCabinet.xRunning := #nState > "E_DeviceState.eStarting" AND #nState <= "E_DeviceState.eUnholding";
	    
	    #stInOutControlUnitCabinet.xMachineOnLed := (#nState > "E_DeviceState.eStarting" AND
	    #nState < "E_DeviceState.eUnholding")
	    OR
	    #nState = "E_DeviceState.eStarting" AND "Clock_2.5Hz"
	    OR
	    #nState = "E_DeviceState.eUnholding" AND "Clock_2.5Hz";
	    
	    #stInOutControlUnitCabinet.xQuitError := (NOT #xQuitErrorFlag AND #xInBtnQuitError) OR #stControl.xQuitt OR #stInOutHMI.xQuit;
	    #stInOutControlUnitCabinet.xSafetyRequest := #nState >= "E_DeviceState.eStarting" AND #nState <= "E_DeviceState.eAborting";
	    #stInOutControlUnitCabinet.xSafetyActive := #xInSafetyActive;
	    IF (NOT #xQuitErrorFlag AND #xInBtnQuitError) THEN
	        #stInOutControlUnitCabinet.xError := 0;
	    END_IF;
	    #xQuitErrorFlag := #xInBtnQuitError;
	    
	    #stInOutControlUnitCabinet.xRestart := #nConveyorStartUpCounter < 6000 AND #nState = "E_DeviceState.eExecute";
	END_REGION
	
	REGION Flags
	    #xQuitErrorFlag := #xInBtnQuitError OR #stInOutHMI.xQuit;
	END_REGION
	
	REGION HMI
	    #stInOutHMI.nStateStatus := #nState; // Für Anzeige
	END_REGION
END_FUNCTION_BLOCK

