{
    S7_Author := "HCR";
    S7_BlockComment := "MLC_56n";
    S7_BlockNumber := "2940";
    S7_BlockTitle := "MLC_3Yu";
    S7_EditorMode := "SCL";
    S7_Family := "ZeusControl";
    S7_IECCheck := "TRUE";
    S7_Optimized := "TRUE";
    S7_Version := "1.0"
}
FUNCTION "FC2940_ZC_TQ_INDV" : Void
    VAR_INPUT
        { S7_MLC := "MLC_3JR" }
        Pulso1seg : Bool;
        { S7_MLC := "MLC_4AZ" }
        Arranque : Bool;
        { S7_MLC := "MLC_3nu" }
        EstadoBocaHombre : Bool;
        { S7_MLC := "MLC_3qH" }
        EstadoNivelBajo : Bool;
        { S7_MLC := "MLC_pu" }
        EstadoNivelAlto : Bool;
        { S7_MLC := "MLC_Vz" }
        EstadoComOK : Bool;
        { S7_MLC := "MLC_56U" }
        ValorNivelPresion : Real;
        { S7_MLC := "MLC_54K" }
        ValorTemperatura : Real;
        { S7_MLC := "MLC_sG" }
        HisteresisAltoNivelAgitacion : Real;
        { S7_MLC := "MLC_4hG" }
        HisteresisBajoNivelAgitacion : Real;
        { S7_MLC := "MLC_49y" }
        HisteresisAltoNivelTemp : Real;
        { S7_MLC := "MLC_4tb" }
        HisteresisBajoNivelTemp : Real;
        { S7_MLC := "MLC_57N" }
        TiempoTanqueVacio : Int;
        { S7_MLC := "MLC_44t" }
        TiempoTanqueLLeno : Int;
        { S7_MLC := "MLC_3AZ" }
        HabilitarFrecAgitacion : Bool;
        { S7_MLC := "MLC_4LF" }
        NumeroTanque : Int;
    END_VAR
    VAR_TEMP
        t_RadioCilindro : Real;
        t_RadioConoInf : Real;
        t_RadioActual : Real;
        t_Vol1 : Real;
        t_Vol2 : Real;
        t_Vol3 : Real;
        t_ConsignaAgitador : Real;
        t_VacioLL : Bool;
        t_VacioEA : Bool;
        t_HistPositiva : Real;
        t_HistNegativa : Real;
        t_LLenoHL : Bool;
        t_LlenoEA : Bool;
        t_x0 : Real;
        t_x1 : Real;
        t_x : Real;
        t_y0 : Real;
        t_y1 : Real;
    END_VAR
    VAR CONSTANT
        CONSTANTE_EMPIRICA : Real := 10.1;
        CONSTANTE_PI : Real := 3.141593;
        ESTADO_DESHABILITADO : Int := 0;
        ESTADO_SUCIO : Int := 1;
        ESTADO_LIMPIO : Int := 2;
        ESTADO_PRODUCTO : Int := 3;
        ESTADO_CIP : Int := 4;
    END_VAR

    { S7_Language := "SCL" }
    NETWORK
        REGION DESCRIPCION
        //=======================================================================
        // (C)Copyright ZeusControl 2022 - 2026
        //=======================================================================
        (*
        ### Información del Sistema
        | Hardware Compatible | Entorno de Ingeniería |
        |---------------------|-----------------------|
        | PLC serie 1200/1500 | TIA Portal 18         |
        
        ---
        ### Descripción Funcional
        El bloque implementa el modelo de dispositivo "Tanque" (`TQ`) para el control integral de depósitos en procesos industriales. Centraliza la adquisición de señales de campo, la gestión de estados del tanque, el cálculo de volumen por geometría cónica-cilíndrica, el control del agitador, el control de temperatura y la supervisión de alarmas, exponiendo toda la información al sistema SCADA mediante direccionamiento multiplexado.
        
        Funcionalidades principales:
        - Gestión del estado global del tanque: deshabilitado, sucio, CIP (limpieza in-situ), limpio y con producto.
        - Lectura y validación de señales digitales y analógicas: detectores de nivel bajo (`LL`), nivel alto (`HL`), boca de hombre, valor de presión y valor de temperatura.
        - Cálculo de la altura de columna de líquido a partir de la presión medida mediante una constante empírica configurable.
        - Cálculo del volumen diferenciando dos tramos geométricos: zona cónica inferior (con radio variable en función del ángulo del cono y radio del cilindro) y zona cilíndrica superior.
        - Detección robusta de tanque vacío y tanque lleno combinando las señales de los detectores con temporizadores (`FC2928_ZC_TON_INDV`) que filtran el volumen por consignas configurables.
        - Gestión de alarmas: nivel bajo, nivel alto, boca de hombre y sobrecapacidad, con agrupación configurable por cuadro para integración en SCADA.
        - Control del agitador con dos modos de operación: fijo (marcha continua) o alternado por tiempos ON/OFF (`FC2926_ZC_FF_INDV`), con consigna de velocidad fija o proporcional al volumen.
        - Control de temperatura en modo calefacción o refrigeración con histéresis configurable y desactivación por nivel mínimo.
        - Seguimiento del producto: registro del producto activo, transición automática entre `Producto1` y `Producto2`, detección de mezcla y borrado al salir del estado PRODUCTO.
        - Soporte de cambio de estado y cambio de producto desde HMI/SCADA mediante flags de orden.
        - Direccionamiento multiplexado para SCADA (no indexado), con reset de índices en el primer arranque del PLC y reubicación del tanque `TQ[0]` cuando el índice vale 0.
        - Contadores de tiempo en estados LIMPIO y PRODUCTO (`FC15025_ZC_CONTADOR_TIEMPO`) para trazabilidad de proceso.
        
        > **Restricciones:** PLC serie 1200/1500.
        
        ---
        ### Dependencias Requeridas
        | Tipo | Elementos |
        |------|-----------|
        | FC   | `FC15025_ZC_CONTADOR_TIEMPO`, `FC2928_ZC_TON_INDV`, `FC2926_ZC_FF_INDV` |
        | FB   | - |
        | DB   | `DB2040_TQ`, `DB1_SYS` |
        | UDT  | `ZC_DISP_TQ`, `ZC_MUX`, `ZC_TON`, `ZC_CONTADOR_TIEMPO` |
            
        ---
        ### Historial de Cambios
        | Versión  | Fecha      | Técnico | Cambios |
        |----------|------------|---------|---------|
        | 01.00.01 | 26.04.2022 | (HCR)   | Primera versión. |
        | 01.00.02 | 09.10.2023 | (HCR)   | Cambio en activación dispositivos para que actúe solamente cuando tenga producto. |
        | 01.00.03 | 15.04.2024 | (ABH)   | Se añade gestión multiplexado para Scada (no indexado). |
        | 01.00.04 | 08.01.2025 | (ABH)   | Se añade entrada de primer arranque del PLC para resetear índices de multiplexado. Se añade movimiento de `TQ[0]` a multiplexado en caso de que el índice sea 0. |
        | 01.00.05 | 24.01.2025 | (ABH)   | Se modifica la lógica del multiplexado, la asignación de `oldindex` se cambia de sitio ya que de vez en cuando (dependiendo de cuándo el HMI realiza la comunicación asíncrona con el PLC) no detectaba el cambio y se machacaban valores. |
        | 01.00.16 | 26.03.2025 | (ABH)   | Se añade variable grupo de alarma para separar los nuevos avisos por cuadro. |
        | 02.00.00 | 17.12.2025 | (ABH)   | Se eliminan los idiomas. Se utiliza códigos para trazabilidad. Se elimina entrada "Idioma". Se elimina nombre de UDT. Se añade `indexHMI` para lista de texto en sistemas de supervisión. |
        *)
        END_REGION DESCRIPCION
        
        
        //  ==========================================================================================================
        REGION LOGICA_DEL_DISPOSITIVO
            
            //  Numero maximo de dispositivos para limitar en HMI/Scada
            "DB2040_TQ".NumDispositivos := "N_MAX_DISP_TQ";
            
            //  Cambio de estado desde HMI/SCADA
            IF "DB2040_TQ".TQ[#NumeroTanque].Orden_CambioEstado THEN
                "DB2040_TQ".TQ[#NumeroTanque].Estado_Tanque := "DB2040_TQ".TQ[#NumeroTanque].Estado_TanqueNuevo;
                "DB2040_TQ".TQ[#NumeroTanque].Orden_CambioEstado := FALSE;
            END_IF;
            
            "DB2040_TQ".TQ[#NumeroTanque].Config_Habilitar := ("DB2040_TQ".TQ[#NumeroTanque].Estado_Tanque <> #ESTADO_DESHABILITADO);
            
            // =============================================================================
            // DISPOSITIVO HABILITADO
            // =============================================================================    
            IF "DB2040_TQ".TQ[#NumeroTanque].Config_Habilitar THEN
                
                REGION LIMITE_GRUPO_ALARMA
                    
                    IF "DB2040_TQ".TQ[#NumeroTanque].Config_GrupoAlarma < 0 THEN
                        "DB2040_TQ".TQ[#NumeroTanque].Config_GrupoAlarma := 0;
                    END_IF;
                    IF "DB2040_TQ".TQ[#NumeroTanque].Config_GrupoAlarma > "N_MAX_DISP_AGRUP" THEN
                        "DB2040_TQ".TQ[#NumeroTanque].Config_GrupoAlarma := "N_MAX_DISP_AGRUP";
                    END_IF;
                    
                END_REGION LIMITE_GRUPO_ALARMA
                
                
                REGION ASIGNAR_ESTADOS
                    
                    // =============================================================================
                    // DETECTOR BOCA DE HOMBRE
                    "DB2040_TQ".TQ[#NumeroTanque].Estado_BocaHombre := #EstadoBocaHombre;
                    // =============================================================================
                    //  DETECTOR LL
                    "DB2040_TQ".TQ[#NumeroTanque].Estado_NivelBajo := #EstadoNivelBajo;
                    // =============================================================================
                    //  DETECTOR HL
                    "DB2040_TQ".TQ[#NumeroTanque].Estado_NivelAlto := #EstadoNivelAlto;
                    // =============================================================================
                    //  LECTURA VALOR NIVEL
                    "DB2040_TQ".TQ[#NumeroTanque].Estado_ValorNivelPresion := #ValorNivelPresion;
                    // =============================================================================
                    //  LECTURA VALOR INGENERIA TEMPERATURA
                    "DB2040_TQ".TQ[#NumeroTanque].Estado_ValorTemperatura := #ValorTemperatura;
                    
                END_REGION ASIGNAR_ESTADOS
                
                
                REGION ALARMAS
                    
                    IF "DB2040_TQ".TQ[#NumeroTanque].Config_HabilitarAlarmas THEN
                        // =============================================================================
                        //  ALARMA DETECTOR NIVEL MÍNIMO
                        "DB2040_TQ".TQ[#NumeroTanque].Alarmas_NivelBajo := NOT "DB2040_TQ".TQ[#NumeroTanque].Estado_NivelBajo;
                        // =============================================================================
                        //  ALARMA DETECTOR NIVEL MÁXIMO
                        "DB2040_TQ".TQ[#NumeroTanque].Alarmas_NivelAlto := "DB2040_TQ".TQ[#NumeroTanque].Estado_NivelAlto;
                        // =============================================================================
                        //  ALARMA DETECTOR BOCA HOMBRE
                        "DB2040_TQ".TQ[#NumeroTanque].Alarmas_BocaHombre := NOT "DB2040_TQ".TQ[#NumeroTanque].Estado_BocaHombre;
                        // =============================================================================
                        //  ALARMA POR CAPACIDAD
                        "DB2040_TQ".TQ[#NumeroTanque].Alarmas_Capacidad := "DB2040_TQ".TQ[#NumeroTanque].Estado_Volumen > "DB2040_TQ".TQ[#NumeroTanque].Config_CapacidadTanque;
                        // =============================================================================
                        //  ALARMA GENERAL
                        "DB2040_TQ".TQ[#NumeroTanque].Alarmas_General := "DB2040_TQ".TQ[#NumeroTanque].Alarmas_NivelBajo OR
                        "DB2040_TQ".TQ[#NumeroTanque].Alarmas_NivelAlto OR
                        "DB2040_TQ".TQ[#NumeroTanque].Alarmas_BocaHombre OR
                        "DB2040_TQ".TQ[#NumeroTanque].Alarmas_Capacidad;
                    ELSE
                        "DB2040_TQ".TQ[#NumeroTanque].Alarmas_General := FALSE;
                        "DB2040_TQ".TQ[#NumeroTanque].Alarmas_NivelBajo := FALSE;
                        "DB2040_TQ".TQ[#NumeroTanque].Alarmas_NivelAlto := FALSE;
                        "DB2040_TQ".TQ[#NumeroTanque].Alarmas_BocaHombre := FALSE;
                        "DB2040_TQ".TQ[#NumeroTanque].Alarmas_Capacidad := FALSE;
                    END_IF;
                    
                END_REGION ALARMAS
                
                
                REGION VOLUMEN
                    
                    REGION ESTADO_VOLUMEN
                        
                        // =============================================================================
                        //  POSICIÓN DE ALTURA
                        //  0 - Altura en cono, 1 - Altura por encima del cono
                        "DB2040_TQ".TQ[#NumeroTanque].Estado_PocisionAltura := ("DB2040_TQ".TQ[#NumeroTanque].Estado_Altura > "DB2040_TQ".TQ[#NumeroTanque].Config_AlturaCono);
                        
                        // =============================================================================
                        //  TANQUE VACÍO DETECTOR
                        #t_VacioLL := "DB2040_TQ".TQ[#NumeroTanque].Alarmas_NivelBajo;
                        // =============================================================================
                        //  TANQUE VACÍO GESTION TON PARA EA < VOLUMEN TANQUE VACIO
                        "DB2040_TQ".TQ[#NumeroTanque].Tiempo_RetTanqueVacio.SP := #TiempoTanqueVacio;
                        "DB2040_TQ".TQ[#NumeroTanque].Tiempo_RetTanqueVacio.IN := ("DB2040_TQ".TQ[#NumeroTanque].Estado_Volumen < "DB2040_TQ".TQ[#NumeroTanque].Config_VolumenTanqueVacio);
                        "FC2928_ZC_TON_INDV"(Pulso1seg := #Pulso1seg,
                                             TON := "DB2040_TQ".TQ[#NumeroTanque].Tiempo_RetTanqueVacio);
                        #t_VacioEA := "DB2040_TQ".TQ[#NumeroTanque].Tiempo_RetTanqueVacio.Q;
                        "DB2040_TQ".TQ[#NumeroTanque].Estado_TanqueVacio := #t_VacioLL OR #t_VacioEA;
                        
                        // =============================================================================
                        //  TANQUE LLENO DETECTOR
                        #t_LLenoHL := "DB2040_TQ".TQ[#NumeroTanque].Alarmas_NivelAlto;
                        // =============================================================================
                        //  TANQUE LLENO GESTION TON PARA EA > VOLUMEN TANQUE LLENO O CAPACIDAD
                        "DB2040_TQ".TQ[#NumeroTanque].Tiempo_RetTanqueLleno.SP := #TiempoTanqueLLeno;
                        "DB2040_TQ".TQ[#NumeroTanque].Tiempo_RetTanqueLleno.IN := (("DB2040_TQ".TQ[#NumeroTanque].Estado_Volumen > "DB2040_TQ".TQ[#NumeroTanque].Config_VolumenTanqueLleno) OR ("DB2040_TQ".TQ[#NumeroTanque].Estado_Volumen > "DB2040_TQ".TQ[#NumeroTanque].Config_CapacidadTanque));
                        "FC2928_ZC_TON_INDV"(Pulso1seg := #Pulso1seg,
                                             TON := "DB2040_TQ".TQ[#NumeroTanque].Tiempo_RetTanqueLleno);
                        #t_LlenoEA := "DB2040_TQ".TQ[#NumeroTanque].Tiempo_RetTanqueLleno.Q;
                        "DB2040_TQ".TQ[#NumeroTanque].Estado_TanqueLleno := #t_LLenoHL OR #t_LlenoEA;
                        
                    END_REGION ESTADO_VOLUMEN
                    
                    
                    REGION CALCULO_VOLUMEN_TANQUE
                        
                        // =============================================================================
                        // SEÑAL EN AUTOMATICO
                        IF NOT "DB2040_TQ".TQ[#NumeroTanque].Estado_AutoMan THEN
                            
                            // =============================================================================
                            // HABILITADO CALCULO DE VOLUMEN
                            IF "DB2040_TQ".TQ[#NumeroTanque].Config_HabilitarCalculoVol THEN
                                // =============================================================================
                                // VALOR PRESION
                                "DB2040_TQ".TQ[#NumeroTanque].Estado_Presion := "DB2040_TQ".TQ[#NumeroTanque].Estado_ValorNivelPresion;
                                
                                // =============================================================================
                                // CÁLCULO DE COLUMNA DE LÍQUIDO
                                "DB2040_TQ".TQ[#NumeroTanque].Estado_Altura := "DB2040_TQ".TQ[#NumeroTanque].Estado_Presion * #CONSTANTE_EMPIRICA;
                                
                                // =============================================================================
                                // CÁLCULO DE DIMENSIONES
                                #t_RadioCilindro := "DB2040_TQ".TQ[#NumeroTanque].Config_DiametroCilindro / 2.0;
                                #t_RadioConoInf := "DB2040_TQ".TQ[#NumeroTanque].Config_DiametroConoInferior / 2.0;
                                #t_RadioActual := #t_RadioCilindro;
                                
                                // =============================================================================
                                // ALTURA INFERIOR AL CONO
                                IF "DB2040_TQ".TQ[#NumeroTanque].Estado_Altura < "DB2040_TQ".TQ[#NumeroTanque].Config_AlturaCono THEN
                                    #t_RadioActual := ("DB2040_TQ".TQ[#NumeroTanque].Estado_Altura / TAN("DB2040_TQ".TQ[#NumeroTanque].Config_AnguloCono)); //+0.13
                                    // =============================================================================
                                    // LÍMITE RADIO
                                    IF #t_RadioActual > #t_RadioCilindro THEN
                                        #t_RadioActual := #t_RadioCilindro;
                                    END_IF;
                                    
                                    // =============================================================================
                                    // CÁLCULO DE VOLUMEN INFERIOR AL CONO
                                    IF "DB2040_TQ".TQ[#NumeroTanque].Estado_Altura > 0 THEN
                                        #t_Vol1 := (#t_RadioConoInf * #t_RadioConoInf) + (#t_RadioActual * #t_RadioActual) + (#t_RadioConoInf * #t_RadioActual);
                                        #t_Vol2 := (#CONSTANTE_PI * "DB2040_TQ".TQ[#NumeroTanque].Estado_Altura) / 3.0;
                                        "DB2040_TQ".TQ[#NumeroTanque].Estado_Volumen := #t_Vol1 * #t_Vol2 * 1000.0;
                                    ELSE
                                        "DB2040_TQ".TQ[#NumeroTanque].Estado_Volumen := 0.0;
                                    END_IF;
                                    // =============================================================================
                                    // ALTURA SUPERIOR AL CONO   
                                ELSE
                                    #t_Vol1 := (#t_RadioConoInf * #t_RadioConoInf) + (#t_RadioActual * #t_RadioActual) + (#t_RadioConoInf * #t_RadioActual);
                                    #t_Vol2 := (#CONSTANTE_PI * "DB2040_TQ".TQ[#NumeroTanque].Estado_Altura) / 3.0;
                                    #t_Vol3 := #CONSTANTE_PI * #t_RadioCilindro * #t_RadioCilindro * ("DB2040_TQ".TQ[#NumeroTanque].Estado_Altura - "DB2040_TQ".TQ[#NumeroTanque].Config_AlturaCono);
                                    "DB2040_TQ".TQ[#NumeroTanque].Estado_Volumen := ((#t_Vol1 * #t_Vol2) + #t_Vol3) * 1000.0;
                                END_IF;
                            ELSE
                                // =============================================================================
                                // VALOR PRESION
                                "DB2040_TQ".TQ[#NumeroTanque].Estado_Volumen := "DB2040_TQ".TQ[#NumeroTanque].Estado_ValorNivelPresion;
                            END_IF;
                            "DB2040_TQ".TQ[#NumeroTanque].Orden_ConsignaManualVolumen := "DB2040_TQ".TQ[#NumeroTanque].Estado_Volumen;
                        ELSE
                            // =============================================================================
                            // ESTADO MANUAL DE EA DE NIVEL   
                            "DB2040_TQ".TQ[#NumeroTanque].Estado_Volumen := "DB2040_TQ".TQ[#NumeroTanque].Orden_ConsignaManualVolumen;
                        END_IF;
                        
                        
                    END_REGION CALCULO_VOLUMEN_TANQUE
                    
                END_REGION VOLUMEN
                
                
                REGION ESTADO
                    
                    // =============================================================================
                    //  ESTADO SUCIO
                    IF "DB2040_TQ".TQ[#NumeroTanque].Estado_Tanque = #ESTADO_PRODUCTO AND "DB2040_TQ".TQ[#NumeroTanque].Estado_TanqueVacio AND #EstadoComOK THEN
                        "DB2040_TQ".TQ[#NumeroTanque].Estado_Tanque := #ESTADO_SUCIO;
                    END_IF;
                    
                    // =============================================================================
                    //  ESTADO CIP
                    IF "DB2040_TQ".TQ[#NumeroTanque].Orden_CIP AND NOT "DB2040_TQ".TQ[#NumeroTanque].Aux_MemEstadoCIP THEN
                        "DB2040_TQ".TQ[#NumeroTanque].Estado_Tanque := #ESTADO_CIP;
                        "DB2040_TQ".TQ[#NumeroTanque].Aux_MemEstadoCIP := "DB2040_TQ".TQ[#NumeroTanque].Orden_CIP;
                    END_IF;
                    
                    // =============================================================================
                    //  ESTADO LIMPIO
                    IF NOT "DB2040_TQ".TQ[#NumeroTanque].Orden_CIP AND "DB2040_TQ".TQ[#NumeroTanque].Aux_MemEstadoCIP THEN
                        IF "DB2040_TQ".TQ[#NumeroTanque].Aux_CipOK THEN
                            "DB2040_TQ".TQ[#NumeroTanque].Estado_Tanque := #ESTADO_LIMPIO;
                        END_IF;
                        "DB2040_TQ".TQ[#NumeroTanque].Aux_MemEstadoCIP := "DB2040_TQ".TQ[#NumeroTanque].Orden_CIP;
                    END_IF;
                    
                    IF "DB2040_TQ".TQ[#NumeroTanque].Estado_Tanque = #ESTADO_CIP AND NOT "DB2040_TQ".TQ[#NumeroTanque].Orden_CIP AND NOT "DB2040_TQ".TQ[#NumeroTanque].Aux_CipOK THEN
                        "DB2040_TQ".TQ[#NumeroTanque].Estado_Tanque := #ESTADO_SUCIO;
                        "DB2040_TQ".TQ[#NumeroTanque].Aux_MemEstadoCIP := "DB2040_TQ".TQ[#NumeroTanque].Orden_CIP;
                    END_IF;
                    
                    //  CONTADOR TIEMPO LIMPIO
                    "FC15025_ZC_CONTADOR_TIEMPO"(Pulso1seg := #Pulso1seg,
                                                 Iniciar := "DB2040_TQ".TQ[#NumeroTanque].Estado_Tanque = #ESTADO_LIMPIO,
                                                 Reset := "DB2040_TQ".TQ[#NumeroTanque].Estado_Tanque <> #ESTADO_LIMPIO,
                                                 Contador := "DB2040_TQ".TQ[#NumeroTanque].Tiempo_TiempoLimpio);
                    
                    // =============================================================================
                    //  ESTADO PRODUCTO
                    IF "DB2040_TQ".TQ[#NumeroTanque].Orden_Producto AND NOT "DB2040_TQ".TQ[#NumeroTanque].Estado_TanqueVacio THEN
                        "DB2040_TQ".TQ[#NumeroTanque].Estado_Tanque := #ESTADO_PRODUCTO;
                    END_IF;
                    
                    
                    // =============================================================================
                    //  CAMBIO DE ESTADO DESDE HMI/SCADA
                    IF "DB2040_TQ".TQ[#NumeroTanque].Orden_CambioProd1 THEN
                        "DB2040_TQ".TQ[#NumeroTanque].Estado_Producto1 := "DB2040_TQ".TQ[#NumeroTanque].Estado_ProductoNuevo;
                        "DB2040_TQ".TQ[#NumeroTanque].Orden_CambioProd1 := FALSE;
                    END_IF;
                    IF "DB2040_TQ".TQ[#NumeroTanque].Orden_CambioProd2 THEN
                        "DB2040_TQ".TQ[#NumeroTanque].Estado_Producto2 := "DB2040_TQ".TQ[#NumeroTanque].Estado_ProductoNuevo;
                        
                        "DB2040_TQ".TQ[#NumeroTanque].Orden_CambioProd2 := FALSE;
                    END_IF;
                    
                    
                    // =============================================================================
                    //  PRODUCTOS
                    IF ("DB2040_TQ".TQ[#NumeroTanque].Estado_Tanque = #ESTADO_PRODUCTO) THEN
                        IF "DB2040_TQ".TQ[#NumeroTanque].Orden_Producto AND NOT "DB2040_TQ".TQ[#NumeroTanque].Aux_MemOrdenProducto THEN
                            IF "DB2040_TQ".TQ[#NumeroTanque].Estado_Producto2 = 0 AND "DB2040_TQ".TQ[#NumeroTanque].Estado_Producto1 <> 0 THEN
                                "DB2040_TQ".TQ[#NumeroTanque].Estado_Producto2 := "DB2040_TQ".TQ[#NumeroTanque].Orden_TipoProducto;
                            END_IF;
                            IF "DB2040_TQ".TQ[#NumeroTanque].Estado_Producto1 = 0 THEN
                                "DB2040_TQ".TQ[#NumeroTanque].Estado_Producto1 := "DB2040_TQ".TQ[#NumeroTanque].Orden_TipoProducto;
                            END_IF;
                        END_IF;
                    END_IF;
                    "DB2040_TQ".TQ[#NumeroTanque].Aux_MemOrdenProducto := "DB2040_TQ".TQ[#NumeroTanque].Orden_Producto;
                    
                    IF NOT "DB2040_TQ".TQ[#NumeroTanque].Orden_Producto OR NOT ("DB2040_TQ".TQ[#NumeroTanque].Estado_Tanque = #ESTADO_PRODUCTO) THEN
                        "DB2040_TQ".TQ[#NumeroTanque].Aux_MemOrdenProducto := FALSE;
                    END_IF;
                    
                    "DB2040_TQ".TQ[#NumeroTanque].Orden_Producto := FALSE;
                    
                    //  CONTADOR TIEMPO PRODUCTO
                    "FC15025_ZC_CONTADOR_TIEMPO"(Pulso1seg := #Pulso1seg,
                                                 Iniciar := "DB2040_TQ".TQ[#NumeroTanque].Estado_Tanque = #ESTADO_PRODUCTO,
                                                 Reset := "DB2040_TQ".TQ[#NumeroTanque].Estado_Tanque <> #ESTADO_PRODUCTO,
                                                 Contador := "DB2040_TQ".TQ[#NumeroTanque].Tiempo_TiempoProducto);
                    
                    // =============================================================================
                    //  TANQUE MEZCLA
                    "DB2040_TQ".TQ[#NumeroTanque].Estado_Mezcla := "DB2040_TQ".TQ[#NumeroTanque].Estado_Producto1 <> 0 AND "DB2040_TQ".TQ[#NumeroTanque].Estado_Producto2 <> 0 AND "DB2040_TQ".TQ[#NumeroTanque].Estado_Producto1 <> "DB2040_TQ".TQ[#NumeroTanque].Estado_Producto2;
                    
                    // =============================================================================
                    //  BORRADO DE PRODUCTOS
                    IF "DB2040_TQ".TQ[#NumeroTanque].Estado_Tanque <> #ESTADO_PRODUCTO THEN
                        "DB2040_TQ".TQ[#NumeroTanque].Estado_Producto1 := 0;
                        "DB2040_TQ".TQ[#NumeroTanque].Estado_Producto2 := 0;
                    END_IF;
                     
                END_REGION ESTADO
                
                
                REGION AGITADOR
                    
                    "DB2040_TQ".TQ[#NumeroTanque].FlipAgitador.Orden_Activar := FALSE;
                    "DB2040_TQ".TQ[#NumeroTanque].Config_HabilitarFrecuenciaAgitacion := #HabilitarFrecAgitacion;
                    
                    // =============================================================================
                    // TANQUE CON AGITADOR 
                    // IF "DB2039_TQ".TQ[N_Tanque].Config_HabilitarAgitador AND NOT "DB2039_TQ".TQ[N_Tanque].Orden_ParoControlAgitador THEN
                    IF "DB2040_TQ".TQ[#NumeroTanque].Config_HabilitarAgitador THEN
                        
                        // =============================================================================
                        // SE AÑADE 50 LITROS POR ENCIMA PARA EMPEZAR A AGITAR
                        IF "DB2040_TQ".TQ[#NumeroTanque].Estado_Volumen > "DB2040_TQ".TQ[#NumeroTanque].Config_VolumenMinControlAgitador + #HisteresisAltoNivelAgitacion THEN
                            "DB2040_TQ".TQ[#NumeroTanque].Aux_MemOrdenAgitador := TRUE;
                        END_IF;
                        // =============================================================================
                        //PARO AGITACIÓN POR NIVEL
                        IF "DB2040_TQ".TQ[#NumeroTanque].Aux_MemOrdenAgitador AND "DB2040_TQ".TQ[#NumeroTanque].Estado_Volumen < "DB2040_TQ".TQ[#NumeroTanque].Config_VolumenMinControlAgitador - #HisteresisBajoNivelAgitacion THEN
                            "DB2040_TQ".TQ[#NumeroTanque].Aux_MemOrdenAgitador := FALSE;
                        END_IF;
                        
                        // =============================================================================
                        //TIPO DE AGITACIÓN POR TIEMPO
                        IF "DB2040_TQ".TQ[#NumeroTanque].Config_TipoAgitacionTiempo = 1 THEN
                            
                            "DB2040_TQ".TQ[#NumeroTanque].FlipAgitador.Config_SetPointTiempoFlip := "DB2040_TQ".TQ[#NumeroTanque].Tiempo_AgitadorONConsigna;
                            "DB2040_TQ".TQ[#NumeroTanque].FlipAgitador.Config_SetPointTiempoFlop := "DB2040_TQ".TQ[#NumeroTanque].Tiempo_AgitadorOFFConsigna;
                            "DB2040_TQ".TQ[#NumeroTanque].FlipAgitador.Orden_Pausa := "DB2040_TQ".TQ[#NumeroTanque].Orden_ParoControlAgitador;
                            "DB2040_TQ".TQ[#NumeroTanque].FlipAgitador.Orden_Activar := "DB2040_TQ".TQ[#NumeroTanque].Aux_MemOrdenAgitador;
                            
                            "FC2926_ZC_FF_INDV"(Pulso1Seg := #Pulso1seg,
                                                FF := "DB2040_TQ".TQ[#NumeroTanque].FlipAgitador);
                            
                            IF "DB2040_TQ".TQ[#NumeroTanque].FlipAgitador.Estado_Flip THEN
                                "DB2040_TQ".TQ[#NumeroTanque].Tiempo_AgitadorONActual := "DB2040_TQ".TQ[#NumeroTanque].FlipAgitador.Aux_Tiempo;
                            ELSE
                                "DB2040_TQ".TQ[#NumeroTanque].Tiempo_AgitadorONActual := 0;
                            END_IF;
                            IF "DB2040_TQ".TQ[#NumeroTanque].FlipAgitador.Estado_Flop THEN
                                "DB2040_TQ".TQ[#NumeroTanque].Tiempo_AgitadorOFFActual := "DB2040_TQ".TQ[#NumeroTanque].FlipAgitador.Aux_Tiempo;
                            ELSE
                                "DB2040_TQ".TQ[#NumeroTanque].Tiempo_AgitadorOFFActual := 0;
                            END_IF;
                            
                        ELSE
                            //  =============================================================================
                            //  TIPO DE AGITACIÓN FIJO
                            "DB2040_TQ".TQ[#NumeroTanque].Tiempo_AgitadorOFFActual := 0;
                            "DB2040_TQ".TQ[#NumeroTanque].Tiempo_AgitadorONActual := 0;
                        END_IF;
                        
                        // =============================================================================
                        //ORDEN ACTIVAR AGITADOR
                        "DB2040_TQ".TQ[#NumeroTanque].Orden_Agitacion :=
                        "DB2040_TQ".TQ[#NumeroTanque].FlipAgitador.Estado_Flip AND
                        NOT "DB2040_TQ".TQ[#NumeroTanque].Orden_ParoControlAgitador AND
                        "DB2040_TQ".TQ[#NumeroTanque].Estado_BocaHombre AND
                        "DB2040_TQ".TQ[#NumeroTanque].Estado_Tanque = #ESTADO_PRODUCTO;
                        
                        // =============================================================================
                        //FRECUENCIA DE AGITADOR
                        IF "DB2040_TQ".TQ[#NumeroTanque].Orden_Agitacion AND "DB2040_TQ".TQ[#NumeroTanque].Config_HabilitarFrecuenciaAgitacion THEN
                            
                            IF "DB2040_TQ".TQ[#NumeroTanque].Config_TipoAgitacionVelocidad = 0 THEN
                                // =============================================================================
                                //VELOCIDAD FIJA
                                "DB2040_TQ".TQ[#NumeroTanque].Orden_ConsignaAgitador := "DB2040_TQ".TQ[#NumeroTanque].Config_VelocidadFijaAgitador;
                                
                            ELSE
                                // =============================================================================
                                //VELOCIDAD POR NIVEL
                                #t_x0 := "DB2040_TQ".TQ[#NumeroTanque].Config_VolumenMinControlAgitador;
                                #t_x1 := "DB2040_TQ".TQ[#NumeroTanque].Config_VolumenMaxControlAgitador;
                                #t_x := "DB2040_TQ".TQ[#NumeroTanque].Estado_Volumen;
                                #t_y0 := "DB2040_TQ".TQ[#NumeroTanque].Config_VelocidadMinAgitador;
                                #t_y1 := "DB2040_TQ".TQ[#NumeroTanque].Config_VelocidadMaxAgitador;
                                #t_ConsignaAgitador := #t_y0 + (#t_y1 - #t_y0) * ((#t_x - #t_x0) / (#t_x1 - #t_x0));
                                IF #t_ConsignaAgitador > #t_y1 THEN
                                    #t_ConsignaAgitador := #t_y1;
                                END_IF;
                                IF #t_ConsignaAgitador < #t_y0 THEN
                                    #t_ConsignaAgitador := #t_y0;
                                END_IF;
                                "DB2040_TQ".TQ[#NumeroTanque].Orden_ConsignaAgitador := #t_ConsignaAgitador;
                            END_IF;
                        ELSE
                            "DB2040_TQ".TQ[#NumeroTanque].Orden_ConsignaAgitador := 0.0;
                            
                        END_IF;
                        
                    ELSE
                        "DB2040_TQ".TQ[#NumeroTanque].Orden_Agitacion := FALSE;
                        "DB2040_TQ".TQ[#NumeroTanque].Aux_MemOrdenAgitador := FALSE;
                        "DB2040_TQ".TQ[#NumeroTanque].Tiempo_AgitadorOFFActual := 0;
                        "DB2040_TQ".TQ[#NumeroTanque].Tiempo_AgitadorONActual := 0;
                        "DB2040_TQ".TQ[#NumeroTanque].Orden_ConsignaAgitador := 0.0;
                    END_IF;
                    
                END_REGION AGITADOR
                
                
                REGION VALVULA
                    
                    // =============================================================================
                    // HABILITAR CONTROL DE TEMPERATURA
                    IF "DB2040_TQ".TQ[#NumeroTanque].Config_HabilitarControlTemp AND NOT "DB2040_TQ".TQ[#NumeroTanque].Orden_ParoControlTemp AND "DB2040_TQ".TQ[#NumeroTanque].Estado_Tanque = #ESTADO_PRODUCTO THEN
                        
                        #t_HistPositiva := "DB2040_TQ".TQ[#NumeroTanque].Config_ConsignaTemperatura + "DB2040_TQ".TQ[#NumeroTanque].Config_HisteresisTemperatura;
                        #t_HistNegativa := "DB2040_TQ".TQ[#NumeroTanque].Config_ConsignaTemperatura - "DB2040_TQ".TQ[#NumeroTanque].Config_HisteresisTemperatura;
                        
                        IF "DB2040_TQ".TQ[#NumeroTanque].Estado_Volumen > "DB2040_TQ".TQ[#NumeroTanque].Config_VolumenMinControlTemp + #HisteresisAltoNivelTemp THEN
                            "DB2040_TQ".TQ[#NumeroTanque].Aux_MemOrdenTemperatura := TRUE;
                            // =============================================================================
                            // CONTROL DE TEMPERATURA ENFRIAR
                            IF "DB2040_TQ".TQ[#NumeroTanque].Config_TipoControlTemperatura THEN
                                
                                IF "DB2040_TQ".TQ[#NumeroTanque].Estado_ValorTemperatura > "DB2040_TQ".TQ[#NumeroTanque].Config_ConsignaTemperatura THEN
                                    "DB2040_TQ".TQ[#NumeroTanque].Orden_Temperatura := TRUE;
                                END_IF;
                                
                                IF "DB2040_TQ".TQ[#NumeroTanque].Estado_ValorTemperatura < #t_HistNegativa THEN
                                    "DB2040_TQ".TQ[#NumeroTanque].Orden_Temperatura := FALSE;
                                END_IF;
                                // =============================================================================
                                // CONTROL DE TEMPERATURA CALENTAR
                            ELSE
                                
                                IF "DB2040_TQ".TQ[#NumeroTanque].Estado_ValorTemperatura < "DB2040_TQ".TQ[#NumeroTanque].Config_ConsignaTemperatura THEN
                                    "DB2040_TQ".TQ[#NumeroTanque].Orden_Temperatura := TRUE;
                                END_IF;
                                
                                IF "DB2040_TQ".TQ[#NumeroTanque].Estado_ValorTemperatura > #t_HistPositiva THEN
                                    "DB2040_TQ".TQ[#NumeroTanque].Orden_Temperatura := FALSE;
                                END_IF;
                                
                            END_IF;
                        END_IF;
                        // =============================================================================
                        //PARAO CONTROL DE TEMPERATURA POR NIVEL
                        IF "DB2040_TQ".TQ[#NumeroTanque].Aux_MemOrdenTemperatura AND "DB2040_TQ".TQ[#NumeroTanque].Estado_Volumen < "DB2040_TQ".TQ[#NumeroTanque].Config_VolumenMinControlTemp - #HisteresisBajoNivelTemp THEN
                            "DB2040_TQ".TQ[#NumeroTanque].Orden_Temperatura := FALSE;
                            "DB2040_TQ".TQ[#NumeroTanque].Aux_MemOrdenTemperatura := FALSE;
                        END_IF;
                        
                    ELSE
                        "DB2040_TQ".TQ[#NumeroTanque].Orden_Temperatura := FALSE;
                    END_IF;
                    
                    // =============================================================================
                    //  VISIBILIDAD CONSIGNA DE TEMPERATURA
                    "DB2040_TQ".TQ[#NumeroTanque].Vis_ConsignaTemperatura :=
                    "DB2040_TQ".TQ[#NumeroTanque].Config_HabilitarControlTemp AND
                    "DB2040_TQ".TQ[#NumeroTanque].Aux_MemOrdenTemperatura AND
                    NOT "DB2040_TQ".TQ[#NumeroTanque].Orden_CIP AND ("DB2040_TQ".TQ[#NumeroTanque].Estado_Tanque = #ESTADO_PRODUCTO) AND
                    NOT "DB2040_TQ".TQ[#NumeroTanque].Orden_ParoControlTemp;
                    
                END_REGION VALVULA
                
            ELSE
                // =============================================================================
                //  DISPOSITIVO DESHABILITADO
                "DB2040_TQ".TQ[#NumeroTanque].Orden_Temperatura := FALSE;
                "DB2040_TQ".TQ[#NumeroTanque].Orden_Agitacion := FALSE;
                "DB2040_TQ".TQ[#NumeroTanque].Orden_ConsignaAgitador := 0.0;
                "DB2040_TQ".TQ[#NumeroTanque].Orden_CIP := FALSE;
                "DB2040_TQ".TQ[#NumeroTanque].Orden_Producto := FALSE;
                
                "DB2040_TQ".TQ[#NumeroTanque].Orden_CambioEstado := FALSE;
                "DB2040_TQ".TQ[#NumeroTanque].Orden_CambioProd1 := FALSE;
                "DB2040_TQ".TQ[#NumeroTanque].Orden_CambioProd2 := FALSE;
                
                "DB2040_TQ".TQ[#NumeroTanque].Aux_MemEstadoCIP := FALSE;
                "DB2040_TQ".TQ[#NumeroTanque].Aux_MemOrdenProducto := FALSE;
                "DB2040_TQ".TQ[#NumeroTanque].Aux_MemOrdenTemperatura := FALSE;
                "DB2040_TQ".TQ[#NumeroTanque].Aux_MemOrdenAgitador := FALSE;
                
                "DB2040_TQ".TQ[#NumeroTanque].Estado_TanqueVacio := FALSE;
                "DB2040_TQ".TQ[#NumeroTanque].Estado_PocisionAltura := FALSE;
                "DB2040_TQ".TQ[#NumeroTanque].Estado_NivelBajo := FALSE;
                "DB2040_TQ".TQ[#NumeroTanque].Estado_NivelAlto := FALSE;
                "DB2040_TQ".TQ[#NumeroTanque].Estado_BocaHombre := FALSE;
                
                "DB2040_TQ".TQ[#NumeroTanque].Estado_Tanque := 0;  //  Deshabilitado
                "DB2040_TQ".TQ[#NumeroTanque].Estado_Producto1 := 0;
                "DB2040_TQ".TQ[#NumeroTanque].Estado_Producto2 := 0;
                
                "DB2040_TQ".TQ[#NumeroTanque].Alarmas_NivelBajo := FALSE;
                "DB2040_TQ".TQ[#NumeroTanque].Alarmas_NivelAlto := FALSE;
                "DB2040_TQ".TQ[#NumeroTanque].Alarmas_BocaHombre := FALSE;
                "DB2040_TQ".TQ[#NumeroTanque].Alarmas_Capacidad := FALSE;
                "DB2040_TQ".TQ[#NumeroTanque].Alarmas_General := FALSE;
                
                "DB2040_TQ".TQ[#NumeroTanque].Estado_Volumen := 0.0;
                "DB2040_TQ".TQ[#NumeroTanque].Estado_Presion := 0.0;
                "DB2040_TQ".TQ[#NumeroTanque].Estado_Altura := 0.0;
                
                "DB2040_TQ".TQ[#NumeroTanque].Config_HabilitarControlTemp := FALSE;
                
                "DB2040_TQ".TQ[#NumeroTanque].Tiempo_AgitadorONActual := 0;
                "DB2040_TQ".TQ[#NumeroTanque].Tiempo_AgitadorOFFActual := 0;
                "DB2040_TQ".TQ[#NumeroTanque].Tiempo_RetTanqueVacio.ET := 0;
                "DB2040_TQ".TQ[#NumeroTanque].Tiempo_RetTanqueVacio.Q := FALSE;
                
                "DB2040_TQ".TQ[#NumeroTanque].Orden_ParoControlAgitador := FALSE;
                "DB2040_TQ".TQ[#NumeroTanque].Orden_ParoControlTemp := FALSE;
                
            END_IF;
            
        END_REGION LOGICA_DEL_DISPOSITIVO
        
    END_NETWORK
END_FUNCTION
