{
    S7_Author := "HCR";
    S7_BlockNumber := "2041";
    S7_BlockTitle := "MLC_562";
    S7_EditorMode := "SCL";
    S7_Family := "ZeusControl";
    S7_Optimized := "TRUE";
    S7_Version := "1.0"
}
FUNCTION "FC2041_ZC_TQ_AE" : Void
    VAR_INPUT
        Pulso1seg : Bool;
        Arranque : Bool;
        Ack : Bool;
        { S7_MLC := "MLC_4jC" }
        UsuarioActual : String;
        { S7_MLC := "MLC_5BC" }
        FechaHoraActual : DTL;
    END_VAR
    VAR_TEMP
        for_i : Int;
        t_N_MAX : Int;
        t_Index : Int;
        t_oldIndex : Int;
        t_CambioDesdeHMI : Bool;
        t_CambioDesdeMux : Bool;
    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
        Bloque de gestión de dispositivos `TQ Aire Estéril`. Realiza la lógica de control, supervisión, alarmas y trazabilidad de los tanques de aire estéril de la planta, así como el multiplexado de los dispositivos hacia los distintos clientes HMI/SCADA.
        
        > **Restricciones:** Ninguna.
        
        Acciones detalladas:
        - Inicializa los índices de multiplexado a `0` en el arranque del PLC.
        - Gestiona los límites del índice (`Index`) y el flag `MaxVisible` para cada cliente HMI/SCADA.
        - Realiza la carga inicial del dispositivo seleccionado al detectar un cambio de índice.
        - Sincroniza los datos de lectura del dispositivo hacia la estructura del multiplexado (`Mux[...]`).
        - Sincroniza los datos de escritura desde el multiplexado hacia el dispositivo, marcando `ExisteCambio` cuando se modifica algún valor.
        - Propaga los cambios realizados desde SCADA al resto de multiplexados que tengan seleccionado el mismo dispositivo.
        - Resetea los flags `AlgunaAlarma` y `AlgunaEnManual` de las agrupaciones de alarma en cada ciclo.
        - Gestiona los modos de trabajo `AutoMan` y la orden `Orden_Manual`.
        - Gestiona las alarmas de configuración, presión baja y presión alta, con temporización de confirmación mediante `Pulso1seg`.
        - Controla la válvula de ducha durante el ciclo CIP mediante lógica flip-flop temporizada.
        - Controla la válvula de venteo, inhibida por las alarmas de presión.
        - Controla la válvula de estéril de forma modulante en función de la presión de trabajo.
        - Registra la trazabilidad de los cambios de modo Auto/Manual y de la activación/desactivación de la orden manual mediante `FC8_ZC_TRAZA_REGISTRO`.
        
        ---
        ### Dependencias Requeridas
        | Tipo | Elementos |
        |------|-----------|
        | FC   | `FC8_ZC_TRAZA_REGISTRO` |
        | FB   | - |
        | DB   | `DB2041_ZC_TQ_AE` |
        | UDT  | `ZC_DISP_TQ_AE` |
            
        ---
        ### Historial de Cambios
        | Versión  | Fecha      | Técnico | Cambios |
        |----------|------------|---------|---------|
        | 00.00.01 | 15.10.2024 | (HCR)   | Primera versión. |
        | 00.00.02 | 28.01.2025 | (ABH)   | Se añade estado AutoMan y orden manual. Se añade trazabilidad. Se añade multiplexado. |
        | 00.00.03 | 26.03.2025 | (ABH)   | Se añade variable grupo de alarma para separar los nuevos avisos por cuadro. |
        | 00.00.04 | 24.04.2025 | (HCR)   | Se añade gestión de idioma. |
        | 00.00.05 | 11.09.2025 | (ABH)   | Se eliminan las constantes de idioma dentro del FC. Se utilizan constantes globales para facilitar su traducción. |
        | 00.00.06 | 17.12.2025 | (ABH)   | Se eliminan los idiomas. Se utiliza códigos para trazabilidad. Se elimina entrada "Idioma". Se elimina nombre de UDT. |
        | 01.00.00 | 08.07.2026 | (ABH)   | Se extrae el multiplexado a FC independiente. |
        *)
        END_REGION DESCRIPCION
        
        
        REGION LOGICA_DEL_DISPOSITIVO
            
            // =============================================================================
            // Resetear todas las alarmas para que se vuelvan a generar
            FOR #for_i := 0 TO "N_MAX_DISP_AGRUP" DO
                "DB2041_TQ_AE".Agrup[#for_i].AlgunaAlarma := FALSE;
                "DB2041_TQ_AE".Agrup[#for_i].AlgunaEnManual := FALSE;
            END_FOR;
            
            //  Numero maximo de dispositivos para limitar en HMI/Scada
            "DB2041_TQ_AE".NumDispositivos := "N_MAX_DISP_TQ_AE";
            
            REGION COMPROBACION_N_MAX
                
                //  Si no hay dispositivos declarados, salimos del bloque inmediatamente
                IF "N_MAX_DISP_TQ_AE" <= 0 THEN
                    RETURN;
                END_IF;
                
                //  Traspaso de N_MAX a variable temporal para evitar fallos de compilacion
                #t_N_MAX := "N_MAX_DISP_TQ_AE";
                
            END_REGION COMPROBACION_N_MAX
            
            FOR #for_i := 1 TO #t_N_MAX DO
                
                
                IF "DB2041_TQ_AE".TQ_AE[#for_i].Config_Habilitar THEN
                    
                    REGION MODOS_DE_TRABAJO
                        
                        // =============================================================================
                        //  MODO MANUAL
                        IF "DB2041_TQ_AE".TQ_AE[#for_i].Estado_AutoMan THEN
                            "DB2041_TQ_AE".Agrup["DB2041_TQ_AE".TQ_AE[#for_i].Config_GrupoAlarma].AlgunaEnManual := TRUE;
                        END_IF;
                        
                        // =============================================================================
                        //  MODO AUTO
                        IF NOT "DB2041_TQ_AE".TQ_AE[#for_i].Estado_AutoMan THEN
                            "DB2041_TQ_AE".TQ_AE[#for_i].Orden_Manual := FALSE;
                        END_IF;
                        
                    END_REGION
                    
                    
                    REGION ALARMAS
                        
                        IF "DB2041_TQ_AE".TQ_AE[#for_i].Config_HabilitarAlarmas THEN
                            
                            // =============================================================================
                            //  ALARMA DE CONFIGURACION
                            "DB2041_TQ_AE".TQ_AE[#for_i].Alarma_Configuracion := TRUE;
                            IF ("DB2041_TQ_AE".TQ_AE[#for_i].Config_PresionMinAlarma < "DB2041_TQ_AE".TQ_AE[#for_i].Config_PresionMinTrabajo) AND
                                ("DB2041_TQ_AE".TQ_AE[#for_i].Config_PresionMinTrabajo < "DB2041_TQ_AE".TQ_AE[#for_i].Config_PresionMaxTrabajo) AND
                                ("DB2041_TQ_AE".TQ_AE[#for_i].Config_PresionMaxTrabajo < "DB2041_TQ_AE".TQ_AE[#for_i].Config_PresionMaxAlarma) THEN
                                "DB2041_TQ_AE".TQ_AE[#for_i].Alarma_Configuracion := FALSE;
                            END_IF;
                            
                            // =============================================================================
                            //  ALARMA MINIMA PRESION
                            "DB2041_TQ_AE".TQ_AE[#for_i].Alarma_PresionBaja := FALSE;
                            IF ("DB2041_TQ_AE".TQ_AE[#for_i].Estado_ValorPresion < "DB2041_TQ_AE".TQ_AE[#for_i].Config_PresionMinAlarma)
                                AND
                                NOT #Ack
                            THEN
                                IF ("DB2041_TQ_AE".TQ_AE[#for_i].Tiempos_AlarmaMinPresion >= "DB2041_TQ_AE".TQ_AE[#for_i].Tiempos_SetPointAlarmaMinPresion) AND "DB2041_TQ_AE".TQ_AE[#for_i].Orden_Vaciado THEN
                                    "DB2041_TQ_AE".TQ_AE[#for_i].Alarma_PresionBaja := TRUE;
                                ELSE
                                    IF #Pulso1seg THEN
                                        "DB2041_TQ_AE".TQ_AE[#for_i].Tiempos_AlarmaMinPresion += 1;
                                    END_IF;
                                END_IF;
                            ELSE
                                "DB2041_TQ_AE".TQ_AE[#for_i].Tiempos_AlarmaMinPresion := 0;
                            END_IF;
                            
                            // =============================================================================
                            //  ALARMA MAXIMA PRESION
                            "DB2041_TQ_AE".TQ_AE[#for_i].Alarma_PresionAlta := FALSE;
                            IF ("DB2041_TQ_AE".TQ_AE[#for_i].Estado_ValorPresion > "DB2041_TQ_AE".TQ_AE[#for_i].Config_PresionMaxAlarma)
                                
                            THEN
                                IF "DB2041_TQ_AE".TQ_AE[#for_i].Tiempos_AlarmaMaxPresion >= "DB2041_TQ_AE".TQ_AE[#for_i].Tiempos_SetPointAlarmaMaxPresion THEN
                                    "DB2041_TQ_AE".TQ_AE[#for_i].Alarma_PresionAlta := TRUE;
                                ELSE
                                    IF #Pulso1seg THEN
                                        "DB2041_TQ_AE".TQ_AE[#for_i].Tiempos_AlarmaMaxPresion += 1;
                                    END_IF;
                                END_IF;
                            ELSE
                                "DB2041_TQ_AE".TQ_AE[#for_i].Tiempos_AlarmaMaxPresion := 0;
                            END_IF;
                            
                        ELSE
                            "DB2041_TQ_AE".TQ_AE[#for_i].Alarma_Configuracion :=
                            "DB2041_TQ_AE".TQ_AE[#for_i].Alarma_PresionAlta :=
                            "DB2041_TQ_AE".TQ_AE[#for_i].Alarma_PresionBaja := FALSE;
                        END_IF;
                        
                    END_REGION
                    
                    
                    REGION VALVULA_DUCHA
                        
                        IF "DB2041_TQ_AE".TQ_AE[#for_i].Orden_CIP AND
                            ("DB2041_TQ_AE".TQ_AE[#for_i].Tiempos_SetPointFlipDucha > 0
                            OR
                            "DB2041_TQ_AE".TQ_AE[#for_i].Tiempos_SetPointFlopDucha > 0)
                        THEN
                            
                            IF "DB2041_TQ_AE".TQ_AE[#for_i].Aux_DuchaFlanco = FALSE THEN
                                "DB2041_TQ_AE".TQ_AE[#for_i].Aux_DuchaSalidaFlop := TRUE;
                                "DB2041_TQ_AE".TQ_AE[#for_i].Aux_DuchaFlanco := TRUE;
                            END_IF;
                            
                            //  =============================================================================
                            //  GESTION TIEMPO FLIP FLOP
                            IF #Pulso1seg THEN
                                
                                //  =============================================================================
                                //  CUENTA FLIP
                                IF "DB2041_TQ_AE".TQ_AE[#for_i].Aux_DuchaFlipActivo = TRUE THEN
                                    "DB2041_TQ_AE".TQ_AE[#for_i].Tiempos_DuchaTiempoFlip += 1;
                                END_IF;
                                
                                //  =============================================================================
                                //  CUENTA FLOP
                                IF "DB2041_TQ_AE".TQ_AE[#for_i].Aux_DuchaFlopActivo = TRUE THEN
                                    "DB2041_TQ_AE".TQ_AE[#for_i].Tiempos_DuchaTiempoFlop += 1;
                                END_IF;
                                
                                //  =============================================================================
                                //  GESTION LOGICA Y SALIDAS FLIP
                                IF "DB2041_TQ_AE".TQ_AE[#for_i].Tiempos_DuchaTiempoFlip >= "DB2041_TQ_AE".TQ_AE[#for_i].Tiempos_SetPointFlipDucha THEN
                                    "DB2041_TQ_AE".TQ_AE[#for_i].Aux_DuchaSalidaFlip := FALSE;
                                    "DB2041_TQ_AE".TQ_AE[#for_i].Aux_DuchaSalidaFlop := TRUE;
                                    "DB2041_TQ_AE".TQ_AE[#for_i].Tiempos_DuchaTiempoFlip := 0;
                                    "DB2041_TQ_AE".TQ_AE[#for_i].Aux_DuchaFlipActivo := false;
                                    "DB2041_TQ_AE".TQ_AE[#for_i].Aux_DuchaFlopActivo := true;
                                END_IF;
                                
                                //  =============================================================================
                                //  GESTION LOGICA Y SALIDAS FLOP
                                IF "DB2041_TQ_AE".TQ_AE[#for_i].Tiempos_DuchaTiempoFlop >= "DB2041_TQ_AE".TQ_AE[#for_i].Tiempos_SetPointFlopDucha THEN
                                    "DB2041_TQ_AE".TQ_AE[#for_i].Aux_DuchaSalidaFlip := TRUE;
                                    "DB2041_TQ_AE".TQ_AE[#for_i].Aux_DuchaSalidaFlop := FALSE;
                                    "DB2041_TQ_AE".TQ_AE[#for_i].Tiempos_DuchaTiempoFlop := 0;
                                    "DB2041_TQ_AE".TQ_AE[#for_i].Aux_DuchaFlipActivo := true;
                                    "DB2041_TQ_AE".TQ_AE[#for_i].Aux_DuchaFlopActivo := false;
                                END_IF;
                                
                            END_IF;
                            
                        END_IF;
                        
                        //  =============================================================================
                        //  GESTION LOGICA SALIDA DUCHA
                        "DB2041_TQ_AE".TQ_AE[#for_i].Salida_ValvulaDucha :=
                        
                        (
                        NOT "DB2041_TQ_AE".TQ_AE[#for_i].Estado_AutoMan
                        AND
                        (
                        "DB2041_TQ_AE".TQ_AE[#for_i].Orden_Produccion
                        OR
                        ("DB2041_TQ_AE".TQ_AE[#for_i].Orden_CIP AND "DB2041_TQ_AE".TQ_AE[#for_i].Aux_DuchaSalidaFlip)
                        )
                        )
                        OR
                        ("DB2041_TQ_AE".TQ_AE[#for_i].Estado_AutoMan AND "DB2041_TQ_AE".TQ_AE[#for_i].Orden_Manual);
                        
                        
                    END_REGION
                    
                    
                    REGION VALVULA_VENTEO
                        
                        //  =============================================================================
                        //  GESTION LOGICA SALIDA VENTEO
                        "DB2041_TQ_AE".TQ_AE[#for_i].Salida_ValvulaVenteo :=
                        (
                        (NOT "DB2041_TQ_AE".TQ_AE[#for_i].Estado_AutoMan AND "DB2041_TQ_AE".TQ_AE[#for_i].Orden_Produccion)
                        OR
                        ("DB2041_TQ_AE".TQ_AE[#for_i].Estado_AutoMan AND "DB2041_TQ_AE".TQ_AE[#for_i].Orden_Manual)
                        )
                        AND
                        NOT "DB2041_TQ_AE".TQ_AE[#for_i].Alarma_PresionAlta AND NOT "DB2041_TQ_AE".TQ_AE[#for_i].Alarma_PresionBaja;
                        
                    END_REGION
                    
                    
                    REGION VALVULA_ESTERIL
                        
                        //  =============================================================================
                        //  GESTION LOGICA SALIDA ESTERIL
                        IF (NOT "DB2041_TQ_AE".TQ_AE[#for_i].Estado_AutoMan AND "DB2041_TQ_AE".TQ_AE[#for_i].Orden_Produccion)
                            OR
                            ("DB2041_TQ_AE".TQ_AE[#for_i].Estado_AutoMan AND "DB2041_TQ_AE".TQ_AE[#for_i].Orden_Manual)
                        THEN
                            IF NOT "DB2041_TQ_AE".TQ_AE[#for_i].Alarma_Configuracion AND NOT "DB2041_TQ_AE".TQ_AE[#for_i].Alarma_PresionBaja THEN
                                IF "DB2041_TQ_AE".TQ_AE[#for_i].Estado_ValorPresion <= "DB2041_TQ_AE".TQ_AE[#for_i].Config_PresionMinTrabajo THEN
                                    "DB2041_TQ_AE".TQ_AE[#for_i].Salida_ValvulaEsteril := TRUE;
                                END_IF;
                                IF "DB2041_TQ_AE".TQ_AE[#for_i].Estado_ValorPresion >= "DB2041_TQ_AE".TQ_AE[#for_i].Config_PresionMaxTrabajo THEN
                                    "DB2041_TQ_AE".TQ_AE[#for_i].Salida_ValvulaEsteril := FALSE;
                                END_IF;
                                
                            ELSE
                                "DB2041_TQ_AE".TQ_AE[#for_i].Salida_ValvulaEsteril := FALSE;
                            END_IF;
                        ELSE
                            "DB2041_TQ_AE".TQ_AE[#for_i].Salida_ValvulaEsteril := FALSE;
                        END_IF;
                        
                    END_REGION
                    
                    
                    REGION TRAZABILIDAD_MANUALIZACION
                        
                        IF "DB2041_TQ_AE".TQ_AE[#for_i].Estado_AutoMan AND NOT "DB2041_TQ_AE".TQ_AE[#for_i].Aux_oldAutoMan THEN
                            "FC8_ZC_TRZ_REGISTRO"(FechaHora := #FechaHoraActual,
                                                    Registrar := 1,
                                                    Categoria := "TRZ_CAT_20_DISP_TQ_AE",
                                                    User := #UsuarioActual,
                                                    CodInt_1 := "TRZ_SYS_DISP_TIPO_TQ_AE",
                                                    CodInt_2 := #for_i,
                                                    CodInt_3 := "TRZ_SYS_DISP_ACC_MAN",
                                                    CodInt_4 := 0,
                                                    CodInt_5 := 0,
                                                    CodReal_1 := 0.0,
                                                    CodReal_2 := 0.0);
                        END_IF;
                        
                        IF NOT "DB2041_TQ_AE".TQ_AE[#for_i].Estado_AutoMan AND "DB2041_TQ_AE".TQ_AE[#for_i].Aux_oldAutoMan THEN
                            "FC8_ZC_TRZ_REGISTRO"(FechaHora := #FechaHoraActual,
                                                    Registrar := 1,
                                                    Categoria := "TRZ_CAT_20_DISP_TQ_AE",
                                                    User := #UsuarioActual,
                                                    CodInt_1 := "TRZ_SYS_DISP_TIPO_TQ_AE",
                                                    CodInt_2 := #for_i,
                                                    CodInt_3 := "TRZ_SYS_DISP_ACC_AUTO",
                                                    CodInt_4 := 0,
                                                    CodInt_5 := 0,
                                                    CodReal_1 := 0.0,
                                                    CodReal_2 := 0.0);
                        END_IF;
                        
                        IF "DB2041_TQ_AE".TQ_AE[#for_i].Estado_AutoMan AND "DB2041_TQ_AE".TQ_AE[#for_i].Orden_Manual AND NOT "DB2041_TQ_AE".TQ_AE[#for_i].Aux_oldOrdenManual THEN
                            "FC8_ZC_TRZ_REGISTRO"(FechaHora := #FechaHoraActual,
                                                    Registrar := 1,
                                                    Categoria := "TRZ_CAT_20_DISP_TQ_AE",
                                                    User := #UsuarioActual,
                                                    CodInt_1 := "TRZ_SYS_DISP_TIPO_TQ_AE",
                                                    CodInt_2 := #for_i,
                                                    CodInt_3 := "TRZ_SYS_DISP_ACC_MAN_ON",
                                                    CodInt_4 := 0,
                                                    CodInt_5 := 0,
                                                    CodReal_1 := 0.0,
                                                    CodReal_2 := 0.0);
                        END_IF;
                        
                        IF "DB2041_TQ_AE".TQ_AE[#for_i].Estado_AutoMan AND NOT "DB2041_TQ_AE".TQ_AE[#for_i].Orden_Manual AND "DB2041_TQ_AE".TQ_AE[#for_i].Aux_oldOrdenManual THEN
                            "FC8_ZC_TRZ_REGISTRO"(FechaHora := #FechaHoraActual,
                                                    Registrar := 1,
                                                    Categoria := "TRZ_CAT_20_DISP_TQ_AE",
                                                    User := #UsuarioActual,
                                                    CodInt_1 := "TRZ_SYS_DISP_TIPO_TQ_AE",
                                                    CodInt_2 := #for_i,
                                                    CodInt_3 := "TRZ_SYS_DISP_ACC_MAN_OFF",
                                                    CodInt_4 := 0,
                                                    CodInt_5 := 0,
                                                    CodReal_1 := 0.0,
                                                    CodReal_2 := 0.0);
                        END_IF;
                        
                    END_REGION
                    
                    
                    // =============================================================================
                    //  Estado anterior manual/automatico
                    "DB2041_TQ_AE".TQ_AE[#for_i].Aux_oldOrdenManual := "DB2041_TQ_AE".TQ_AE[#for_i].Orden_Manual;
                    "DB2041_TQ_AE".TQ_AE[#for_i].Aux_oldAutoMan := "DB2041_TQ_AE".TQ_AE[#for_i].Estado_AutoMan;
                    
                ELSE
                    
                    // =============================================================================
                    //  INICIALIZACIÓN DE SALIDAS
                    "DB2041_TQ_AE".TQ_AE[#for_i].Estado_AutoMan :=
                    "DB2041_TQ_AE".TQ_AE[#for_i].Orden_Manual :=
                    "DB2041_TQ_AE".TQ_AE[#for_i].Orden_Produccion :=
                    "DB2041_TQ_AE".TQ_AE[#for_i].Orden_CIP :=
                    "DB2041_TQ_AE".TQ_AE[#for_i].Orden_Vaciado :=
                    "DB2041_TQ_AE".TQ_AE[#for_i].Alarma_Configuracion :=
                    "DB2041_TQ_AE".TQ_AE[#for_i].Alarma_PresionAlta :=
                    "DB2041_TQ_AE".TQ_AE[#for_i].Alarma_PresionBaja :=
                    "DB2041_TQ_AE".TQ_AE[#for_i].Salida_ValvulaDucha :=
                    "DB2041_TQ_AE".TQ_AE[#for_i].Salida_ValvulaEsteril :=
                    "DB2041_TQ_AE".TQ_AE[#for_i].Salida_ValvulaVenteo := FALSE;
                    
                END_IF;
                
            END_FOR;
            
        END_REGION
        
        
    END_NETWORK
END_FUNCTION
