{
    S7_Author := "ABH";
    S7_BlockComment := "MLC_sz";
    S7_BlockNumber := "2026";
    S7_BlockTitle := "MLC_5BL";
    S7_EditorMode := "SCL";
    S7_Family := "ZeusControl";
    S7_Optimized := "TRUE";
    S7_Version := "1.0"
}
FUNCTION "FC2026_ZC_FF" : Void
    VAR_INPUT
        { S7_MLC := "MLC_NU" }
        Pulso1Seg : Bool;
    END_VAR
    VAR_TEMP
        for_i : Int;
        t_N_MAX : Int;
    END_VAR
    VAR CONSTANT
        REPOSO : SInt := 0;
        FLOP : SInt := 10;
        PARO1 : SInt := 20;
        FLIP : SInt := 30;
        PARO2 : SInt := 40;
    END_VAR

    { S7_Language := "SCL" }
    NETWORK
        REGION DESCRIPCION
        (*
        ###### (C)Copyright ZeusControl 2020 - 2026
        
        ---
        ### Información del Sistema
        | Hardware Compatible | Entorno de Ingeniería |
        |---------------------|-----------------------|
        | PLC serie 1200/1500 | TIA Portal 18         |
        
        ---
        > **Restricciones:** Ninguna.
        
        ---
        ### Descripción Funcional
        
        Función encargada de gestionar un dispositivo flip flop con funcion de paro entre cambios.
        
        Las tareas que realiza son las siguientes:
        
        - Gestionar la activacion y calculos de tiempo de cambio entre ordenes Flip, Flop y paro.
        - Adicionalmente, se gestiona tambien la posibilidad de pausar el contaje del tiempo, para evitar su reinicializacion en caso de pausa.
        - En los cambios entre ´flip´ <--> ´flop´, se activa tambien la marca ´paro´ para poder gestionar los cambios y evitar golpes de ariete.
        
        ---
        ### Dependencias Requeridas
        | Tipo | Elementos |
        |------|-----------|
        | FC   | - |
        | FB   | - |
        | DB   | `DB2026_FF` |
        | UDT  | `UDT_ZC_DISP_FF_PARO` |
        
        ---
        ### Historial de Cambios
        | Versión  | Fecha      | Técnico | Cambios |
        |----------|------------|---------|---------|
        | 00.00.01 | 10.08.2020 | (ABH)   | Primera version. |
        | 00.00.02 | 02.10.2020 | (ABH)   | Cambio en la logica del dispositivo, ya que al cambio de flip a flop, se perdia un segundo del contaje de tienmpo. |
        | 00.00.03 | 28.11.2023 | (ABH)   | Se añade condicion de activacion del Flip Flop a que algun SP sea mayor que 0.. |
        | 00.00.04 | 15.10.2025 | (ABH)   | Se añade orden pausa para dejar de contar. |
        | 01.00.00 | 06.07.2026 | (ABH)   | Refactorizacion de logica para optimizacion. Se añade ordenes de paro (opcionales) para su uso para evitar golpes de ariete. |
        *)
        END_REGION DESCRIPCION
        
        
        REGION COMPROBACION_N_MAX
            
            //  Si no hay dispositivos declarados, salimos del bloque inmediatamente
            IF "N_MAX_DISP_FF" <= 0 THEN
                RETURN;
            END_IF;
            
            //  Traspaso de N_MAX a variable temporal para evitar fallos de compilacion
            #t_N_MAX := "N_MAX_DISP_FF";
            
        END_REGION COMPROBACION_N_MAX
        
            
        //  ==========================================================================================================
        REGION GESTION_DISPOSITIVO
            
            FOR #for_i := 1 TO #t_N_MAX DO
                
                // ==========================================================================================================
                REGION COMPROBACIONES_INICIALES
                    
                    //  Si no hay orden o faltan tiempos, reseteamos valores y salimos de la funcion
                    IF NOT "DB2026_FF".FF[#for_i].Orden_Activar OR ("DB2026_FF".FF[#for_i].Config_SetPointTiempoFlip <= 0 AND "DB2026_FF".FF[#for_i].Config_SetPointTiempoFlop <= 0) THEN
                        "DB2026_FF".FF[#for_i].Estado_Flip := FALSE;
                        "DB2026_FF".FF[#for_i].Estado_Flop := FALSE;
                        "DB2026_FF".FF[#for_i].Estado_Paro1 := FALSE;
                        "DB2026_FF".FF[#for_i].Estado_Paro2 := FALSE;
                        
                        "DB2026_FF".FF[#for_i].Aux_Tiempo := 0;
                        "DB2026_FF".FF[#for_i].Estado_Etapa := #REPOSO;
                        
                        "DB2026_FF".FF[#for_i].Aux_Inicializado := FALSE;
                        RETURN;
                    END_IF;
                    
                END_REGION COMPROBACIONES_INICIALES
                
                
                // ==========================================================================================================
                REGION INICIALIZACION
                    
                    //  Arranque inicial forzado a Flop si no hay estado activo
                    IF NOT "DB2026_FF".FF[#for_i].Aux_Inicializado THEN
                        "DB2026_FF".FF[#for_i].Estado_Etapa := #FLOP;
                        "DB2026_FF".FF[#for_i].Aux_Inicializado := TRUE;
                    END_IF;
                    
                END_REGION INICIALIZACION
                
                
                // ==========================================================================================================
                REGION LOGICA_DE_ESTADOS
                    
                    CASE "DB2026_FF".FF[#for_i].Estado_Etapa OF
                            
                        #FLOP:
                            //  Salidas
                            "DB2026_FF".FF[#for_i].Estado_Flip := FALSE;
                            "DB2026_FF".FF[#for_i].Estado_Flop := TRUE;
                            "DB2026_FF".FF[#for_i].Estado_Paro1 := FALSE;
                            "DB2026_FF".FF[#for_i].Estado_Paro2 := FALSE;
                            
                            //  Conteo de tiempo
                            IF #Pulso1Seg AND NOT "DB2026_FF".FF[#for_i].Orden_Pausa THEN
                                "DB2026_FF".FF[#for_i].Aux_Tiempo += 1;
                            END_IF;
                            
                            //  Transición
                            IF "DB2026_FF".FF[#for_i].Aux_Tiempo >= "DB2026_FF".FF[#for_i].Config_SetPointTiempoFlop THEN
                                "DB2026_FF".FF[#for_i].Aux_Tiempo := 0;
                                //  Si no tenemos tiempo de paro configurado, saltamos a FLIP
                                IF "DB2026_FF".FF[#for_i].Config_SetPointTiempoParo <= 0 THEN
                                    "DB2026_FF".FF[#for_i].Estado_Etapa := #FLIP;
                                ELSE
                                    "DB2026_FF".FF[#for_i].Estado_Etapa := #PARO1;
                                END_IF;
                            END_IF;
                            
                        #PARO1:
                            //  Salidas
                            "DB2026_FF".FF[#for_i].Estado_Flip := FALSE;
                            "DB2026_FF".FF[#for_i].Estado_Flop := FALSE;
                            "DB2026_FF".FF[#for_i].Estado_Paro1 := TRUE;
                            "DB2026_FF".FF[#for_i].Estado_Paro2 := FALSE;
                            
                            //  Conteo de tiempo
                            IF #Pulso1Seg AND NOT "DB2026_FF".FF[#for_i].Orden_Pausa THEN
                                "DB2026_FF".FF[#for_i].Aux_Tiempo += 1;
                            END_IF;
                            
                            //  Transición
                            IF "DB2026_FF".FF[#for_i].Aux_Tiempo >= "DB2026_FF".FF[#for_i].Config_SetPointTiempoParo THEN
                                "DB2026_FF".FF[#for_i].Aux_Tiempo := 0;
                                "DB2026_FF".FF[#for_i].Estado_Etapa := #FLIP;
                            END_IF;
                            
                            
                        #FLIP:
                            //  Salidas
                            "DB2026_FF".FF[#for_i].Estado_Flip := TRUE;
                            "DB2026_FF".FF[#for_i].Estado_Flop := FALSE;
                            "DB2026_FF".FF[#for_i].Estado_Paro1 := FALSE;
                            "DB2026_FF".FF[#for_i].Estado_Paro2 := FALSE;
                            
                            //  Conteo de tiempo
                            IF #Pulso1Seg AND NOT "DB2026_FF".FF[#for_i].Orden_Pausa THEN
                                "DB2026_FF".FF[#for_i].Aux_Tiempo += 1;
                            END_IF;
                            
                            //  Transición
                            IF "DB2026_FF".FF[#for_i].Aux_Tiempo >= "DB2026_FF".FF[#for_i].Config_SetPointTiempoFlip THEN
                                "DB2026_FF".FF[#for_i].Aux_Tiempo := 0;
                                //  Si no tenemos tiempo de paro configurado, saltamos a FLOP
                                IF "DB2026_FF".FF[#for_i].Config_SetPointTiempoParo <= 0 THEN
                                    "DB2026_FF".FF[#for_i].Estado_Etapa := #FLOP;
                                ELSE
                                    "DB2026_FF".FF[#for_i].Estado_Etapa := #PARO2;
                                END_IF;
                            END_IF;
                            
                            
                        #PARO2:
                            //  Salidas
                            "DB2026_FF".FF[#for_i].Estado_Flip := FALSE;
                            "DB2026_FF".FF[#for_i].Estado_Flop := FALSE;
                            "DB2026_FF".FF[#for_i].Estado_Paro1 := FALSE;
                            "DB2026_FF".FF[#for_i].Estado_Paro2 := TRUE;
                            
                            //  Conteo de tiempo
                            IF #Pulso1Seg AND NOT "DB2026_FF".FF[#for_i].Orden_Pausa THEN
                                "DB2026_FF".FF[#for_i].Aux_Tiempo += 1;
                            END_IF;
                            
                            //  Transición
                            IF "DB2026_FF".FF[#for_i].Aux_Tiempo >= "DB2026_FF".FF[#for_i].Config_SetPointTiempoParo THEN
                                "DB2026_FF".FF[#for_i].Aux_Tiempo := 0;
                                "DB2026_FF".FF[#for_i].Estado_Etapa := #FLOP;
                            END_IF;
                            
                        ELSE
                            "DB2026_FF".FF[#for_i].Estado_Etapa := #REPOSO;
                    END_CASE;
                    
                END_REGION LOGICA_DE_ESTADOS 
                
            END_FOR;
        
        END_REGION GESTION_DISPOSITIVO
        
        
    END_NETWORK
END_FUNCTION
