{
    S7_Author := "ABH";
    S7_BlockComment := "MLC_3dc";
    S7_BlockNumber := "15053";
    S7_BlockTitle := "MLC_4CE";
    S7_EditorMode := "SCL";
    S7_Family := "ZeusControl";
    S7_IECCheck := "TRUE";
    S7_Optimized := "TRUE";
    S7_Version := "1.0"
}
FUNCTION_BLOCK "FB15053_ZC_INF_LIMP_MAQ"
    VAR_INPUT
        { S7_MLC := "MLC_3Yk" }
        EnLimpieza : Bool;
        { S7_MLC := "MLC_4nN" }
        LimpBasica1 : Bool;
        { S7_MLC := "MLC_4ZQ" }
        LimpAcida : Bool;
        { S7_MLC := "MLC_VF" }
        LimpBasica2 : Bool;
        { S7_MLC := "MLC_U2" }
        Pulso1Seg : Bool;
        {
            S7_Access := "ReadOnly := External";
            S7_MLC := "MLC_3B9";
            S7_Visibility := "Hidden := External"
        }
        FechaHoraActual : DTL;
        { S7_MLC := "MLC_58X" }
        TempBasica1 : LReal;
        { S7_MLC := "MLC_3Dj" }
        CTLimpBasica1 : LReal;
        { S7_MLC := "MLC_3Xc" }
        CTEnjBasica1 : LReal;
        { S7_MLC := "MLC_4Q4" }
        PorcentajeQRefBasica1 : LReal;
        { S7_MLC := "MLC_3CU" }
        TempAcida : LReal;
        { S7_MLC := "MLC_498" }
        CTLimpAcida : LReal;
        { S7_MLC := "MLC_ts" }
        CTEnjAcida : LReal;
        { S7_MLC := "MLC_wE" }
        PorcentajeQRefAcida : LReal;
        { S7_MLC := "MLC_4QK" }
        TempBasica2 : LReal;
        { S7_MLC := "MLC_44s" }
        CTLimpBasica2 : LReal;
        { S7_MLC := "MLC_4Uu" }
        CTEnjBasica2 : LReal;
        { S7_MLC := "MLC_kx" }
        PorcentajeQRefBasica2 : LReal;
        { S7_MLC := "MLC_3SY" }
        TipoLimpieza : Int;
        { S7_MLC := "MLC_SN" }
        TiempoLimpieza : _.UDT_ZC_CONTADOR_TIEMPO;
    END_VAR
    VAR_IN_OUT
        { S7_MLC := "MLC_4zC" }
        Informe : Array[*] of _.UDT_ZC_INF_LIMP_MAQ;
    END_VAR
    VAR
        {
            S7_MLC := "MLC_Se";
            S7_Setpoint := "True"
        }
        s_OrdenInicioInforme : Bool;
        {
            S7_MLC := "MLC_3mL";
            S7_Setpoint := "True"
        }
        s_OrdenFinInforme : Bool;
    END_VAR
    VAR RETAIN
        {
            S7_MLC := "MLC_4Yk";
            S7_Setpoint := "True"
        }
        s_oldInicio : Bool;
        {
            S7_MLC := "MLC_3nr";
            S7_Setpoint := "True"
        }
        s_oldFin : Bool;
    END_VAR
    VAR
        { S7_MLC := "MLC_qg" }
        s_OrdenBorrarInforme : Bool;
        { S7_MLC := "MLC_52x" }
        s_NumeroBorrado : Int;
    END_VAR
    VAR RETAIN
        { S7_MLC := "MLC_44P" }
        TiempoRecircBasica1 : Int;
        { S7_MLC := "MLC_3j2" }
        TiempoRecircAcida : Int;
        { S7_MLC := "MLC_LX" }
        TiempoRecircBasica2 : Int;
    END_VAR
    VAR_TEMP
        for_i : Int;
        t_dummyInt : Int;
        { S7_MLC := "MLC_4PQ" }
        t_IndiceSuperior : Int;
        { S7_MLC := "MLC_3xQ" }
        t_IndiceInferior : Int;
        t_InformeVacio : _.UDT_ZC_INF_LIMP_MAQ;
    END_VAR
    VAR CONSTANT
        ACTUAL : Int := 1;
    END_VAR

    { S7_Language := "SCL" }
    NETWORK
        REGION DESCRIPCION
        //=======================================================================
        // (C)Copyright ZeusControl 2025 - 2026
        //=======================================================================
        (*
        ### Información del Sistema
        | Hardware Compatible | Entorno de Ingeniería |
        |---------------------|-----------------------|
        | PLC serie 1200/1500 | TIA Portal 18         |
        
        ---
        ### Descripción Funcional
        Bloque de funcion que implementa la gestión de los datos de informe de limpieza de la máquina, manteniendo un histórico de hasta `#N_REGISTROS` limpiezas con todos los datos relevantes de cada fase (básica 1, ácida y básica 2): tiempo total, tipo de limpieza, temperaturas, conductividades de limpieza y enjuague, porcentaje de caudal de referencia y tiempo de recirculación por etapa. Se utiliza en máquinas de membranas para trazabilidad y consulta desde el sistema de supervisión.
        
        Funcionalidades principales:
        - Detección de flanco ascendente y descendente en `#EnLimpieza` mediante las variables estáticas `#s_P_Trig_Inicio` y `#s_P_Trig_Fin`, generando el pulso de inicio `#s_OrdenInicioInforme` y el de fin `#s_OrdenFinInforme`.
        - Inicialización del informe: al recibir `#s_OrdenInicioInforme` se desplazan los informes existentes una posición hacia abajo mediante `MOVE_BLK_VARIANT`, se reinicializan a cero los contadores internos de recirculación (`#TiempoRecircBasica1`, `#TiempoRecircAcida`, `#TiempoRecircBasica2`) y los campos del nuevo informe activo (`#Informe[1]`: tipo de limpieza, tiempos de recirculación por fase, tiempo total, temperaturas, conductividades y porcentajes de caudal de referencia de cada fase). Se almacena la fecha/hora de inicio mediante la conversión realizada por `FC15005_ZC_DTL_TO_ZC_FECHA`.
        - Datos en curso: mientras `#EnLimpieza` está activo, se incrementan los contadores de tiempo de recirculación de cada fase (`#TiempoRecircBasica1`, `#TiempoRecircAcida`, `#TiempoRecircBasica2`) cuando el pulso de 1 segundo y el flag de fase correspondiente (`#LimpBasica1`, `#LimpAcida`, `#LimpBasica2`) están activos, y se copian en `#Informe[1]` los valores de proceso en tiempo real: tipo de limpieza, tiempo total de limpieza, temperatura, conductividad de limpieza, conductividad de enjuague, porcentaje de caudal de referencia y tiempo de recirculación para cada una de las tres fases.
        - Fin de informe: al detectar `#s_OrdenFinInforme` se registra la fecha/hora de fin en `#Informe[1].FechaFin`.
        - Borrado masivo: la entrada `#s_Borrar` permite limpiar completamente todos los registros del array, inicializando fechas, tipo de limpieza, tiempos de recirculación, tiempo total, temperaturas, conductividades y porcentajes de caudal de referencia a sus valores neutros. La propia variable de orden se autodesactiva tras la operación.
        
        > **Restricciones:** Ninguna.
        
        ---
        ### Dependencias Requeridas
        | Tipo | Elementos |
        |------|-----------|
        | FC   | `FC15005_ZC_DTL_TO_ZC_FECHA` |
        | FB   | - |
        | DB   | - |
        | UDT  | `UDT_ZC_CONTADOR_TIEMPO`, `ZC_INF_LIMP_MAQ` |
            
        ---
        ### Historial de Cambios
        | Versión  | Fecha      | Técnico | Cambios |
        |----------|------------|---------|---------|
        | 01.00.00 | 10.11.2025 | (CNR)   | Primera versión. |
        | 01.00.01 | 03.07.2026 | (ABH)   | Cambio a SCL. |
        *)
        END_REGION DESCRIPCION
        
        
        //  ==========================================================================================================
        REGION LIMITES
            
            //  Calculo limites array de informes
            #t_IndiceInferior := DINT_TO_INT(LOWER_BOUND(ARR := #Informe, DIM := 1));
            #t_IndiceSuperior := DINT_TO_INT(UPPER_BOUND(ARR := #Informe, DIM := 1));
            
            //  Si no hay informes configurados, salimos inmediatamente.
            IF #t_IndiceInferior <= 0 THEN
                RETURN;
            END_IF;
            
        END_REGION LIMITES
        
        
        //  ==========================================================================================================
        REGION GESTION_ORDENES
            
            //  Orden inicio produccion
            #s_OrdenInicioInforme := #EnLimpieza AND NOT #s_oldInicio;
            
            //  Orden fin produccion
            #s_OrdenFinInforme := NOT #EnLimpieza AND #s_oldFin;
            
            //  Estados anteriores
            #s_oldInicio := #EnLimpieza;
            #s_oldFin := #EnLimpieza;
            
        END_REGION GESTION_ORDENES
        
        
        //  ==========================================================================================================
        REGION INICIALIZACION
            
            //  Con flanco de inicio informe, desplazamos los registros, reinicializamos los datos y almacenamos la fecha y hora de inicio, todo en la poisicion 1
            IF #s_OrdenInicioInforme THEN
                
                
                //  Desplazamiento de datos
                #t_dummyInt := MOVE_BLK_VARIANT(SRC := #Informe, COUNT := INT_TO_UDINT(#t_IndiceSuperior - 1), SRC_INDEX := 0, DEST_INDEX := 1, DEST => #Informe);
                
                //  Reinicializacion de los datos
                #Informe[#ACTUAL] := #t_InformeVacio;
                
                #TiempoRecircBasica1 := 0;
                #TiempoRecircAcida := 0;
                #TiempoRecircBasica2 := 0;
                
                //  Guardado de fecha y hora actual
                #Informe[#ACTUAL].FechaInicio := "FC15005_ZC_DTL_TO_ZC_FECHA"(FechaDTL := #FechaHoraActual);
                
            END_IF;
            
        END_REGION INICIALIZACION
        
        
        //  ==========================================================================================================
        REGION DATOS_DURANTE_PRODUCCION
            
            //  Se guardan los datos durante la produccion
            IF #EnLimpieza THEN
                
                IF #Pulso1Seg AND #LimpBasica1 THEN
                    #TiempoRecircBasica1 += 1;
                END_IF;
                IF #Pulso1Seg AND #LimpAcida THEN
                    #TiempoRecircAcida += 1;
                END_IF;
                IF #Pulso1Seg AND #LimpBasica2 THEN
                    #TiempoRecircBasica2 += 1;
                END_IF;
                
                #Informe[#ACTUAL].TipoLimpieza := #TipoLimpieza;
                
                #Informe[#ACTUAL].TiempoLimpieza.Hora := #TiempoLimpieza.Hora;
                #Informe[#ACTUAL].TiempoLimpieza.Minuto := #TiempoLimpieza.Minuto;
                #Informe[#ACTUAL].TiempoLimpieza.Segundo := #TiempoLimpieza.Segundo;
                
                #Informe[#ACTUAL].TempBasica1 := #TempBasica1;
                #Informe[#ACTUAL].CTLimpBasica1 := #CTLimpBasica1;
                #Informe[#ACTUAL].CTEnjBasica1 := #CTEnjBasica1;
                #Informe[#ACTUAL].PorcentajeQRefBasica1 := #PorcentajeQRefBasica1;
                #Informe[#ACTUAL].TiempoRecircBasica1 := #TiempoRecircBasica1;
                
                #Informe[#ACTUAL].TempAcida := #TempAcida;
                #Informe[#ACTUAL].CTLimpAcida := #CTLimpAcida;
                #Informe[#ACTUAL].CTEnjAcida := #CTEnjAcida;
                #Informe[#ACTUAL].PorcentajeQRefAcida := #PorcentajeQRefAcida;
                #Informe[#ACTUAL].TiempoRecircAcida := #TiempoRecircAcida;
                
                #Informe[#ACTUAL].TempBasica2 := #TempBasica2;
                #Informe[#ACTUAL].CTLimpBasica2 := #CTLimpBasica2;
                #Informe[#ACTUAL].CTEnjBasica2 := #CTEnjBasica2;
                #Informe[#ACTUAL].PorcentajeQRefBasica2 := #PorcentajeQRefBasica2;
                #Informe[#ACTUAL].TiempoRecircBasica2 := #TiempoRecircBasica2;
                
            END_IF;
            
        END_REGION DATOS_DURANTE_PRODUCCION
        
        
        //  ==========================================================================================================
        REGION FIN_INFORME
            
            //  Se guardan los datos durante la produccion
            IF #s_OrdenFinInforme THEN
                
                //  Guardado de fecha y hora actual
                #Informe[#ACTUAL].FechaFin := "FC15005_ZC_DTL_TO_ZC_FECHA"(FechaDTL := #FechaHoraActual);
                
            END_IF;
            
        END_REGION FIN_INFORME
        
        
        //  ==========================================================================================================
        REGION BORRADO_DATOS
            
            //  Borrado de todos los registros
            IF #s_OrdenBorrarInforme THEN
                IF #s_NumeroBorrado = -1 OR #s_NumeroBorrado = 0 THEN
                
                FOR #for_i := 1 TO #t_IndiceSuperior DO
                    #Informe[#for_i] := #t_InformeVacio;
                END_FOR;
                
            ELSIF #s_NumeroBorrado >= 1 AND #s_NumeroBorrado < #t_IndiceSuperior THEN
                
                //  Borrado registro especifico
                #Informe[#s_NumeroBorrado] := #t_InformeVacio;
                
                //  Desplazamiento de datos
                #t_dummyInt := MOVE_BLK_VARIANT(SRC := #Informe,
                                                COUNT := INT_TO_UDINT(#t_IndiceSuperior - #s_NumeroBorrado),
                                                SRC_INDEX := #s_NumeroBorrado,
                                                DEST_INDEX := #s_NumeroBorrado - 1,
                                                DEST => #Informe);
                
                //  Borrado del ultimo registro
                #Informe[#t_IndiceSuperior] := #t_InformeVacio;
                
            ELSIF #s_NumeroBorrado = #t_IndiceSuperior THEN
                
                //  Borrado de ultimo registro
                #Informe[#s_NumeroBorrado] := #t_InformeVacio;
                
            END_IF;
            
            #s_OrdenBorrarInforme := FALSE;
            
        END_IF;
            
        END_REGION BORRADO_DATOS
        
    END_NETWORK
END_FUNCTION_BLOCK
