FUNCTION_BLOCK "FB_StockRemovalSequencer"
{ S7_Optimized_Access := 'TRUE' }
VERSION : 0.1
   VAR_INPUT 
      arrx_IN_SystemReady : Array[1..3] of Bool;   // Fördertechnik frei
      udt_IN_BlockMap : "udt_BlockMap";
      x_IN_Reset : Bool;
   END_VAR

   VAR_OUTPUT 
      n_OUT_ActiveIndex : Int;   // Aktives Lager (0 = keines)
      x_OUT_AnyActive : Bool;   // TRUE, wenn eines gerade aktiv ist
   END_VAR

   VAR_IN_OUT 
      udt_INOUT_StorageArray : "udt_StorageArray";
   END_VAR

   VAR 
      nSequence : Int;   // 0=IDLE, 2=WAIT_DONE
      nLastServed : Int;
      nNextIdx : Int;
      xFound : Bool;
      xBlockIdx : Int;
   END_VAR

   VAR_TEMP 
      n_Temp_startIdx : Int;
      n_Temp_checkIdx : Int;
      n_Temp_count : Int;
      n_Temp_BlockMapIdx : Int;
   END_VAR

   VAR CONSTANT 
      c000_Wait : Int := 0;
      c010_SetRelease : Int := 10;
   END_VAR


BEGIN
	
	
	
	
	
	
	
	
	
	
	REGION Logik
	    
	    IF #x_IN_Reset THEN
	        #nSequence := 0;
	        #n_OUT_ActiveIndex := 0;
	        #nLastServed := 0;
	        #x_OUT_AnyActive := FALSE;
	        
	        FOR #xBlockIdx := 1 TO 12 DO
	            #udt_INOUT_StorageArray.arrudt_StorageCtrl[#xBlockIdx].xRelease := FALSE;
	        END_FOR;
	    ELSE
	        // Nächsten Kandidaten im Round-Robin suchen
	        #xFound := FALSE;
	        #nNextIdx := 0;
	        
	        
	        //Sorgt für Rundlauf
	        #n_Temp_startIdx := #nLastServed + 1;
	        IF #n_Temp_startIdx > 12 THEN
	            #n_Temp_startIdx := 1;
	        END_IF;
	        
	        //Suche nach Request ab dem letzten Lager das ausgelagert hat / verhindert endlosen Loop
	        #n_Temp_checkIdx := #n_Temp_startIdx;
	        FOR #n_Temp_count := 1 TO 12 DO
	            #n_Temp_BlockMapIdx := #udt_IN_BlockMap.arrn_BlockOf[#n_Temp_checkIdx];          // Block 1..3
	            IF #udt_INOUT_StorageArray.arrudt_StorageState[#n_Temp_checkIdx].xRequest
	                AND (#n_Temp_BlockMapIdx >= 1) AND (#n_Temp_BlockMapIdx <= 3)
	                AND (#arrx_IN_SystemReady[#n_Temp_BlockMapIdx])
	            THEN
	                #nNextIdx := #n_Temp_checkIdx;
	                #xFound := TRUE;
	                EXIT;
	            END_IF;
	            #n_Temp_checkIdx := #n_Temp_checkIdx + 1;
	            IF #n_Temp_checkIdx > 12 THEN
	                #n_Temp_checkIdx := 1;
	            END_IF;
	        END_FOR;
	        
	        CASE #nSequence OF
	                
	            #c000_Wait:
	                #x_OUT_AnyActive := FALSE;
	                #n_OUT_ActiveIndex := 0;
	                // Alle Freigaben sicher zurücksetzen
	                FOR #xBlockIdx := 1 TO 12 DO
	                    #udt_INOUT_StorageArray.arrudt_StorageCtrl[#xBlockIdx].xRelease := FALSE;
	                END_FOR;
	                // Nur starten, wenn ein anfragendes Lager UND dessen Block ready
	                IF  #xFound THEN
	                    #n_OUT_ActiveIndex := #nNextIdx;
	                    #udt_INOUT_StorageArray.arrudt_StorageCtrl[#n_OUT_ActiveIndex].xRelease := TRUE;
	                    #x_OUT_AnyActive := TRUE;
	                    #nSequence := #c010_SetRelease;
	                END_IF;
	                
	                // ---------------- WAIT_DONE ----------------
	            #c010_SetRelease:
	                #x_OUT_AnyActive := TRUE;
	                // Exklusivität sicherstellen
	                FOR #xBlockIdx := 1 TO 12 DO
	                    #udt_INOUT_StorageArray.arrudt_StorageCtrl[#xBlockIdx].xRelease := (#xBlockIdx = #n_OUT_ActiveIndex);
	                END_FOR;
	                // Abschlussbedingung: Done ODER Anfrage abgebrochen
	                IF #udt_INOUT_StorageArray.arrudt_StorageState[#n_OUT_ActiveIndex].xDone
	                    OR NOT #udt_INOUT_StorageArray.arrudt_StorageState[#n_OUT_ActiveIndex].xRequest THEN
	                    #udt_INOUT_StorageArray.arrudt_StorageCtrl[#n_OUT_ActiveIndex].xRelease := FALSE;
	                    #x_OUT_AnyActive := FALSE;
	                    #nLastServed := #n_OUT_ActiveIndex;
	                    #n_OUT_ActiveIndex := 0;
	                    // Direkt nächsten starten, falls vorhanden (Block-ready geprüft)
	                    IF  #xFound THEN
	                        #n_OUT_ActiveIndex := #nNextIdx;
	                        #udt_INOUT_StorageArray.arrudt_StorageCtrl[#n_OUT_ActiveIndex].xRelease := TRUE;
	                        #x_OUT_AnyActive := TRUE;
	                        #nSequence := #c010_SetRelease;
	                    ELSE
	                        #nSequence := #c010_SetRelease;
	                    END_IF;
	                END_IF;
	                
	            ELSE
	                #nSequence := #c000_Wait;
	        END_CASE;
	        
	        
	        
	        
	        
	    END_IF;
	END_REGION
	
	
	
	
END_FUNCTION_BLOCK

