{
    S7_Author := "ABH";
    S7_BlockNumber := "15050";
    S7_BlockTitle := "MLC_3nk";
    S7_EditorMode := "SCL";
    S7_Family := "ZeusControl";
    S7_IECCheck := "TRUE";
    S7_Optimized := "TRUE";
    S7_Version := "1.0"
}
FUNCTION_BLOCK "FB15050_ZC_CHEQUEO"
    VAR_INPUT
        { S7_MLC := "MLC_4bi" }
        GuardarRegistro : Bool;
        { S7_MLC := "MLC_4AB" }
        ComprobarBajoChequeo : Bool;
        { S7_MLC := "MLC_4UZ" }
        ResetBajoChequeo : Bool;
        { S7_MLC := "MLC_4xM" }
        TomarDatoChequeo : Bool;
        { S7_MLC := "MLC_4b8" }
        PorcentajeBomba : Real;
        { S7_MLC := "MLC_fD" }
        Temperatura : Real;
        { S7_MLC := "MLC_4Lf" }
        Caudal : Real;
        { S7_MLC := "MLC_3KS" }
        CaudalPermeado : Real;
        { S7_MLC := "MLC_uX" }
        Conductividad : Real;
        { S7_MLC := "MLC_4fJ" }
        Presion : Real;
        { S7_MLC := "MLC_4Gs" }
        SP_Caudal_100por100 : Real;
        { S7_MLC := "MLC_s7" }
        SP_CaudalMinimoChequeo : Real;
        { S7_MLC := "MLC_3vu" }
        FechaActual : DTL;
    END_VAR
    VAR_OUTPUT
        { S7_MLC := "MLC_3Gf" }
        EstadoChequeoActual : Bool;
        { S7_MLC := "MLC_4Dm" }
        AlarmaBajoChequeo : Bool;
        { S7_MLC := "MLC_4bh" }
        VisDatoChequeo : Bool;
        { S7_MLC := "MLC_4mf" }
        PorcentajeChequeoActual : Real;
    END_VAR
    VAR RETAIN
        {
            S7_Access := "ReadOnly := External";
            S7_Visibility := "Hidden := External"
        }
        s_PorcentajeChequeoOK : Real := 80.0;
    END_VAR
    VAR
        {
            S7_Access := "ReadOnly := External";
            S7_Visibility := "Hidden := External"
        }
        s_OrdenGuardarRegistro : Bool;
        {
            S7_Access := "ReadOnly := External";
            S7_Visibility := "Hidden := External"
        }
        s_OrdenBorrarRegistros : Bool;
        {
            S7_Access := "ReadOnly := External";
            S7_MLC := "MLC_3NF";
            S7_Visibility := "Hidden := External"
        }
        s_NumeroBorrado : Int;
        {
            S7_Access := "ReadOnly := External";
            S7_Visibility := "Hidden := External"
        }
        s_OldGuardar : Bool;
    END_VAR
    VAR RETAIN
        { S7_Setpoint := "False" }
        Registro : Array[1..#N_REGISTROS] of _.UDT_ZC_INF_CHEQUEO;
    END_VAR
    VAR_TEMP
        for_i : Int;
        t_dummyInt : Int;
    END_VAR
    VAR CONSTANT
        N_REGISTROS : Int := 20;
    END_VAR

    { S7_Language := "SCL" }
    NETWORK
        REGION DESCRIPCION
        //=======================================================================
        // (C)Copyright ZeusControl 2024 - 2026
        //=======================================================================
        (*
        ### Información del Sistema
        | Hardware Compatible | Entorno de Ingeniería |
        |---------------------|-----------------------|
        | PLC serie 1200/1500 | TIA Portal 18         |
        
        ---
        ### Descripción Funcional
        El bloque `FB15050_ZC_CHEQUEO` implementa la gestión de los datos de chequeo de un sistema de membranas, manteniendo un histórico circular de hasta `#N_REGISTROS` mediciones y evaluando el rendimiento de la instalación comparando el caudal de permeado real con un valor de referencia al 100% de la bomba.
        
        Funcionalidades principales:
        - Detección de flanco ascendente en la orden de guardado: `#s_OrdenGuardarRegistro` se activa con un pulso de `#GuardarRegistro` mediante la variable estática `#s_P_Trig_Guardar`, evitando registros duplicados por nivel alto mantenido.
        - Adquisición de datos: al recibir la orden de guardado, se desplazan los registros existentes una posición hacia abajo mediante `MOVE_BLK_VARIANT` y se almacena en `#Registro[1]` el conjunto de variables de proceso (`PorcentajeBomba`, `Temperatura`, `Caudal`, `CaudalPermeado`, `Conductividad`, `Presion`), junto con el `ResultadoChequeo` calculado como el porcentaje de caudal de permeado frente a `SP_Caudal_100por100`, y la fecha actual convertida con `FC15005_ZC_DTL_TO_ZC_FECHA` a la estructura `ZC_FECHA`.
        - Cálculo del porcentaje de chequeo en tiempo real: `PorcentajeChequeoActual` se obtiene como el cociente entre el `CaudalPermeado` actual y `SP_Caudal_100por100`, y `EstadoChequeoActual` se activa cuando dicho porcentaje alcanza o supera `#s_PorcentajeChequeoOK`.
        - Alarma de bajo chequeo: se activa `#AlarmaBajoChequeo` cuando `#ComprobarBajoChequeo` está habilitado y el `Caudal` cae por debajo de `#SP_CaudalMinimoChequeo`. Se desactiva con `#ResetBajoChequeo`.
        - Animación de resultados: para cada registro se evalúa `ResultadoAnimacion`, que se activa cuando el `ResultadoChequeo` del registro es igual o superior a 80.0%, permitiendo al HMI colorear el histórico de forma intuitiva.
        - Visibilidad de toma de dato en HMI: `VisDatoChequeo` refleja el estado de `#TomarDatoChequeo` para señalizar al operador que la fase de toma de datos está activa.
        - Borrado de registros selectivo: según el valor de `#s_NumeroBorrado` se distingue entre borrado total (`0` o `-1`), borrado de un registro intermedio (con desplazamiento hacia abajo para mantener la trazabilidad) y borrado del último registro. En todos los casos se inicializan a cero todos los campos del registro (analógicos y de fecha).
        
        > **Restricciones:** Ninguna.
        
        ---
        ### Dependencias Requeridas
        | Tipo | Elementos |
        |------|-----------|
        | FC   | `FC15005_ZC_DTL_TO_ZC_FECHA` |
        | FB   | - |
        | DB   | - |
        | UDT  | `ZC_FECHA`, `ZC_CHEQUEO` |
            
        ---
        ### Historial de Cambios
        | Versión  | Fecha      | Técnico | Cambios |
        |----------|------------|---------|---------|
        | 01.00.00 | 18.07.2023 | (ABH)   | Primera versión. |
        | 01.00.01 | 21.07.2023 | (ABH)   | Se eliminan entradas `Etapa actual` y `tiempo restante`. La gestión de guardado y comprobación de bajo chequeo se realiza mediante entradas BOOL. |
        | 01.00.02 | 11.10.2023 | (HCR)   | Se añaden entradas `TomarDatoChequeo` y salida `VisDatoChequeo` para mostrar en HMI la toma de datos por parte del operador. |
        | 01.00.02 | 03.07.2026 | (ABH)   | Cambio a SCL. |
        *)
        END_REGION DESCRIPCION
        
        
        //  ==========================================================================================================
        REGION ORDEN_GUARDAR
            
            //  Orden guardar registro
            #s_OrdenGuardarRegistro := #GuardarRegistro AND NOT #s_OldGuardar;
            
            //  Estado anterior
            #s_OldGuardar := #GuardarRegistro;
            
        END_REGION ORDEN_GUARDAR
        
        
        //  ==========================================================================================================
        REGION ADQUISICION_DE_DATOS
            
            //  Con flanco de guardar datos, desplazamos los registros y almacenamos los datos del chequeo en la poisicion 1
            IF #s_OrdenGuardarRegistro THEN
                
                //  Desplazamiento de datos
                #t_dummyInt := MOVE_BLK_VARIANT(SRC := #Registro, COUNT := INT_TO_UDINT(#N_REGISTROS - 1), SRC_INDEX := 0, DEST_INDEX := 1, DEST => #Registro);
                
                //  Adquisicion de datos
                #Registro[1].PorcentajeBomba := #PorcentajeBomba;
                #Registro[1].Temperatura := #Temperatura;
                #Registro[1].Caudal := #Caudal;
                #Registro[1].CaudalPermeado := #CaudalPermeado;
                #Registro[1].Conductividad := #Conductividad;
                #Registro[1].Presion := #Presion;
                #Registro[1].ResultadoChequeo := #CaudalPermeado / #SP_Caudal_100por100 * 100.0;
                
                #Registro[1].Fecha := "FC15005_ZC_DTL_TO_ZC_FECHA"(#FechaActual);
                
            END_IF;
            
        END_REGION ADQUISICION_DE_DATOS
        
        
        //  ==========================================================================================================
        REGION CALCULO_%_CHEQUEO
            
            //  Calculo porcentaje del chequeo
            IF #SP_Caudal_100por100 > 0.0 THEN
                #PorcentajeChequeoActual := (#Registro[1].CaudalPermeado / #SP_Caudal_100por100) * 100.0;
            ELSE
                #PorcentajeChequeoActual := 0.0;
            END_IF;
            
            //  Estado del chequeo actual
            #EstadoChequeoActual := #PorcentajeChequeoActual >= #s_PorcentajeChequeoOK;
            
        END_REGION CALCULO_%_CHEQUEO
        
        
        //  ==========================================================================================================
        REGION VISIBILIDADES
            
            //  Visibilidad bajo chequeo
            IF #ComprobarBajoChequeo AND (#Caudal < #SP_CaudalMinimoChequeo) THEN
                #AlarmaBajoChequeo := TRUE;
            END_IF;
            IF #ResetBajoChequeo THEN
                #AlarmaBajoChequeo := FALSE;
            END_IF;
            
            //  Visibilidad Resultado Chequeo
            FOR #for_i := 1 TO #N_REGISTROS DO
                #Registro[#for_i].ResultadoAnimacion := (#Registro[#for_i].ResultadoChequeo >= 80.0);
            END_FOR;
            
            //  Visibilidad tomar dato chequeo en HMI
            #VisDatoChequeo := #TomarDatoChequeo;
            
        END_REGION VISIBILIDADES
        
        
        //  ==========================================================================================================
        REGION BORRADO
            
            //  Borrado de todos los registros
            IF #s_OrdenBorrarRegistros THEN
                IF #s_NumeroBorrado = -1 OR #s_NumeroBorrado = 0 THEN
                    //  ==============================================================================
                    //  Borrado total
                    FOR #for_i := 1 TO #N_REGISTROS DO
                        #Registro[#for_i].PorcentajeBomba := 0.0;
                        #Registro[#for_i].Temperatura := 0.0;
                        #Registro[#for_i].Caudal := 0.0;
                        #Registro[#for_i].CaudalPermeado := 0.0;
                        #Registro[#for_i].Conductividad := 0.0;
                        #Registro[#for_i].Presion := 0.0;
                        #Registro[#for_i].ResultadoChequeo := 0.0;
                        #Registro[#for_i].Fecha.Ano := 0;
                        #Registro[#for_i].Fecha.Mes := 0;
                        #Registro[#for_i].Fecha.Dia := 0;
                        #Registro[#for_i].Fecha.DiaSemana := 0;
                        #Registro[#for_i].Fecha.Hora := 0;
                        #Registro[#for_i].Fecha.Minuto := 0;
                        #Registro[#for_i].Fecha.Segundo := 0;
                        #Registro[#for_i].Fecha.NanoSegundo := 0;
                    END_FOR;
                ELSIF #s_NumeroBorrado >= 1 AND #s_NumeroBorrado < #N_REGISTROS THEN
                    //  ==============================================================================
                    //  Borrado registro especifico
                    #Registro[#s_NumeroBorrado].PorcentajeBomba := 0.0;
                    #Registro[#s_NumeroBorrado].Temperatura := 0.0;
                    #Registro[#s_NumeroBorrado].Caudal := 0.0;
                    #Registro[#s_NumeroBorrado].CaudalPermeado := 0.0;
                    #Registro[#s_NumeroBorrado].Conductividad := 0.0;
                    #Registro[#s_NumeroBorrado].Presion := 0.0;
                    #Registro[#s_NumeroBorrado].ResultadoChequeo := 0.0;
                    #Registro[#s_NumeroBorrado].Fecha.Ano := 0;
                    #Registro[#s_NumeroBorrado].Fecha.Mes := 0;
                    #Registro[#s_NumeroBorrado].Fecha.Dia := 0;
                    #Registro[#s_NumeroBorrado].Fecha.DiaSemana := 0;
                    #Registro[#s_NumeroBorrado].Fecha.Hora := 0;
                    #Registro[#s_NumeroBorrado].Fecha.Minuto := 0;
                    #Registro[#s_NumeroBorrado].Fecha.Segundo := 0;
                    #Registro[#s_NumeroBorrado].Fecha.NanoSegundo := 0;
                    //  ==============================================================================
                    //  Desplazamiento de datos
                    #t_dummyInt := MOVE_BLK_VARIANT(SRC := #Registro,
                                                    COUNT := INT_TO_UDINT(#N_REGISTROS - #s_NumeroBorrado),
                                                    SRC_INDEX := #s_NumeroBorrado,
                                                    DEST_INDEX := #s_NumeroBorrado - 1,
                                                    DEST => #Registro);
                    //  ==============================================================================
                    //  Borrado del ultimo registro
                    #Registro[#N_REGISTROS].PorcentajeBomba := 0.0;
                    #Registro[#N_REGISTROS].Temperatura := 0.0;
                    #Registro[#N_REGISTROS].Caudal := 0.0;
                    #Registro[#N_REGISTROS].CaudalPermeado := 0.0;
                    #Registro[#N_REGISTROS].Conductividad := 0.0;
                    #Registro[#N_REGISTROS].Presion := 0.0;
                    #Registro[#N_REGISTROS].ResultadoChequeo := 0.0;
                    #Registro[#N_REGISTROS].Fecha.Ano := 0;
                    #Registro[#N_REGISTROS].Fecha.Mes := 0;
                    #Registro[#N_REGISTROS].Fecha.Dia := 0;
                    #Registro[#N_REGISTROS].Fecha.DiaSemana := 0;
                    #Registro[#N_REGISTROS].Fecha.Hora := 0;
                    #Registro[#N_REGISTROS].Fecha.Minuto := 0;
                    #Registro[#N_REGISTROS].Fecha.Segundo := 0;
                    #Registro[#N_REGISTROS].Fecha.NanoSegundo := 0;
                ELSIF #s_NumeroBorrado = #N_REGISTROS THEN
                    //  ==============================================================================
                    //  Borrado de ultimo registro
                    #Registro[#s_NumeroBorrado].PorcentajeBomba := 0.0;
                    #Registro[#s_NumeroBorrado].Temperatura := 0.0;
                    #Registro[#s_NumeroBorrado].Caudal := 0.0;
                    #Registro[#s_NumeroBorrado].CaudalPermeado := 0.0;
                    #Registro[#s_NumeroBorrado].Conductividad := 0.0;
                    #Registro[#s_NumeroBorrado].Presion := 0.0;
                    #Registro[#s_NumeroBorrado].ResultadoChequeo := 0.0;
                    #Registro[#s_NumeroBorrado].Fecha.Ano := 0;
                    #Registro[#s_NumeroBorrado].Fecha.Mes := 0;
                    #Registro[#s_NumeroBorrado].Fecha.Dia := 0;
                    #Registro[#s_NumeroBorrado].Fecha.DiaSemana := 0;
                    #Registro[#s_NumeroBorrado].Fecha.Hora := 0;
                    #Registro[#s_NumeroBorrado].Fecha.Minuto := 0;
                    #Registro[#s_NumeroBorrado].Fecha.Segundo := 0;
                    #Registro[#s_NumeroBorrado].Fecha.NanoSegundo := 0;
                END_IF;
                #s_OrdenBorrarRegistros := FALSE;
            END_IF;
            
        END_REGION BORRADO
        
        
    END_NETWORK
END_FUNCTION_BLOCK
