FUNCTION "FC2000_ZC_ED" : Void
TITLE = FC2000_ED
{ S7_Optimized_Access := 'TRUE' }
AUTHOR : HCR
FAMILY : ZeusControl
VERSION : 1.0
//Modelo de dispositivo Entrada digital
   VAR_INPUT 
      Pulso1seg : Bool;   // Pulso de 1 segundo
      Simulacion : Bool;   // Simulacion
      UsuarioActual : String;   // Usuario actual
      FechaHoraActual {InstructionName := 'DTL'; LibVersion := '1.0'} : DTL;   // Fecha y hora actual
   END_VAR

   VAR_TEMP 
      for_i : Int;
      t_N_MAX : Int;
      t_ValorEntrada : Bool;
   END_VAR

   VAR CONSTANT 
      TIPO_ACCESO_INDIRECTO : SInt := 0;
      TIPO_ACCESO_PLC : SInt := 1;
   END_VAR


BEGIN
	REGION DESCRIPCION
	(*
	###### (C)Copyright ZeusControl 2020 - 2026
	
	---
	### Información del Sistema
	| Hardware Compatible | Entorno de Ingeniería |
	|---------------------|-----------------------|
	| PLC serie 1200/1500 | TIA Portal 18         |
	
	---
	> **Restricciones:** Ninguna.
	
	---
	### Descripción Funcional
	
	Funcion para la gestion de dispositivo de tipo Entrada Digital.
	
	En ella se realizan las siguientes acciones:
	
	- Se gestiona el multiplexado de los dispositivos para su uso en sistemas HMI/SCADA.
	- Se realiza la lectura de la entrada de manera indirecta si esta habilitada.
	- Se gestiona el estado del dispositivo
	- Se gestiona la trazabilidad de las manualizaciones del dispositivo
	
	---
	### Dependencias Requeridas
	| Tipo | Elementos |
	|------|-----------|
	| FC   | `FC8_ZC_TRAZA_REGISTRO` |
	| FB   | - |
	| DB   | `DB2000_ED` |
	| UDT  | - |
	    
	---
	### Historial de Cambios
	| Versión  | Fecha      | Técnico | Cambios |
	|----------|------------|---------|---------|
	| 00.00.01 | 15.10.2020 | (ABH)   | Primera version. |
	| 00.01.00 | 26.04.2022 | (HCR)   | Cambio en la organizacion del UDT. Se organiza en estructuras en base al tipo de funcion que realizan los datos. |
	| 00.02.00 | 27.04.2022 | (ABH)   | Se añaden auxiliares de estado anterior del modo manual y automatico para poder registrar las trazas. |
	| 00.00.03 | 22.02.2024 | (ABH)   | Se añade gestion multiplexado para Scada (no indexado) |
	| 00.00.04 | 08.01.2025 | (ABH)   | Se añade entrada de primer arranque del PLC para resetear indices de multiplexado. Se añade movimiento de SD[0] a multiplexado en caso de que el indice sea 0. |
	| 00.00.05 | 24.01.2025 | (ABH)   | Se modifica la logica del multiplexado, la asignacion de oldindex se cambia de sitio ya que de vez en cuando (dependiendo de cuando el HMI realiza la comunicacion asincrona con el PLC) no detectaba el cambio y se machacaban valores. |
	| 00.00.06 | 26.03.2025 | (ABH)   | Se añade variable grupo de alarma para separar los nuevos avisos por cuadro. |
	| 00.00.07 | 24.04.2025 | (HCR)   | Se añade gestion de idioma  |
	| 00.00.08 | 11.09.2025 | (ABH)   | Se eliminan las constantes de idioma dentro del FC. Se utilizan constantes globales para facilitar su traduccion. |
	| 00.00.09 | 17.12.2025 | (ABH)   | Se eliminan los idiomas. Se utiliza codigos para trazabilidad. Se elimina entrada "Idioma". Se elimina nombre de UDT. Se elimina nombre de UDT. Se añade indexHMI para lista de texto en sistemas de supervision. |
	| 00.00.00 | 18.05.2026 | (ABH)   | Se añade variable `Config_TipoAcceso` para uso de direccionamiento indirecto o uso directo en PLC. |
	| 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
	        "DB2000_ED".Agrup[#for_i].AlgunaAlarma := FALSE;
	        "DB2000_ED".Agrup[#for_i].AlgunaEnManual := FALSE;
	    END_FOR;
	    
	    //  Numero maximo de dispositivos para limitar en HMI/Scada
	    "DB2000_ED".Mux.NumDispositivos := "N_MAX_DISP_ED";
	    
	    REGION COMPROBACION_N_MAX
	        
	        //  Si no hay dispositivos declarados, salimos del bloque inmediatamente
	        IF "N_MAX_DISP_ED" <= 0 THEN
	            RETURN;
	        END_IF;
	    
	        //  Traspaso de N_MAX a variable temporal para evitar fallos de compilacion
	        #t_N_MAX := "N_MAX_DISP_ED";
	    
	    END_REGION COMPROBACION_N_MAX
	    
	    FOR #for_i := 1 TO #t_N_MAX DO
	        
	        // =============================================================================
	        // DISPOSITIVO HABILITADO
	        // =============================================================================
	        IF "DB2000_ED".ED[#for_i].Config_Habilitar THEN
	            
	            REGION LIMITE_GRUPO_ALARMA
	                
	                IF "DB2000_ED".ED[#for_i].Config_GrupoAlarma < 0 THEN
	                    "DB2000_ED".ED[#for_i].Config_GrupoAlarma := 0;
	                END_IF;
	                IF "DB2000_ED".ED[#for_i].Config_GrupoAlarma > "N_MAX_DISP_AGRUP" THEN
	                    "DB2000_ED".ED[#for_i].Config_GrupoAlarma := "N_MAX_DISP_AGRUP";
	                END_IF;
	                
	            END_REGION LIMITE_GRUPO_ALARMA
	            
	            
	            REGION LECTURA_VALORES
	                
	                CASE "DB2000_ED".ED[#for_i].Config_TipoAcceso OF
	                        
	                    #TIPO_ACCESO_INDIRECTO:
	                        IF "DB2000_ED".ED[#for_i].Config_DirEntradaByte >= 0 THEN
	                            (*
	                            AREA: Pueden seleccionarse las siguientes áreas: 
	                            16#81: Input, 
	                            16#82: Output, 
	                            16#83: Marcas, 
	                            16#84: DB, 
	                            16#1: Entrada de periferia (solo S7-1500)
	                            DBNUMBER: Número del bloque de datos si AREA = DB, de lo contrario "0"
	                            BYTEOFFSET: Dirección en la que se lee. Solo se utilizan los 16 bits menos significativos.*)
	                            #t_ValorEntrada := PEEK_BOOL(area := 16#81,
	                                                         dbNumber := 0,
	                                                         byteOffset := "DB2000_ED".ED[#for_i].Config_DirEntradaByte,
	                                                         bitOffset := "DB2000_ED".ED[#for_i].Config_DirEntradaBit);
	                            
	                            IF NOT "DB2000_ED".ED[#for_i].Config_HabilitarInvertir THEN
	                                "DB2000_ED".ED[#for_i].Estado_EntradaCanal := NOT #t_ValorEntrada;
	                            ELSE
	                                "DB2000_ED".ED[#for_i].Estado_EntradaCanal := #t_ValorEntrada;
	                            END_IF;
	                            
	                        END_IF;
	                        
	                    #TIPO_ACCESO_PLC:
	                        ;
	                        
	                END_CASE;
	                
	            END_REGION LECTURA_VALORES
	            
	            
	            REGION MODOS_DE_TRABAJO
	                
	                // =============================================================================
	                //  MODO MANUAL
	                IF "DB2000_ED".ED[#for_i].Estado_AutoMan THEN
	                    
	                    "DB2000_ED".Agrup["DB2000_ED".ED[#for_i].Config_GrupoAlarma].AlgunaEnManual := TRUE;
	                    
	                    IF "DB2000_ED".ED[#for_i].Orden_ActivarManual THEN
	                        "DB2000_ED".ED[#for_i].Estado_Activado := TRUE;
	                    ELSE
	                        "DB2000_ED".ED[#for_i].Estado_Activado := FALSE;
	                        "DB2000_ED".ED[#for_i].Orden_ActivarManual := FALSE;
	                    END_IF;
	                    
	                ELSE
	                    "DB2000_ED".ED[#for_i].Orden_ActivarManual := "DB2000_ED".ED[#for_i].Estado_Activado;
	                END_IF;
	                
	            END_REGION MODOS_DE_TRABAJO
	            
	            
	            REGION ESTADO_DEL_DISPOSITIVO
	                
	                // =============================================================================
	                //  DETECTOR SIMULADO
	                IF #Simulacion THEN
	                    
	                    IF "DB2000_ED".ED[#for_i].Orden_ActivarManual THEN
	                        "DB2000_ED".ED[#for_i].Estado_Activado := TRUE;
	                    ELSE
	                        "DB2000_ED".ED[#for_i].Estado_Activado := FALSE;
	                    END_IF;
	                END_IF;
	                
	                
	                IF NOT "DB2000_ED".ED[#for_i].Estado_AutoMan AND NOT #Simulacion THEN
	                    
	                    // =============================================================================
	                    //  RETARDO A LA ACTIVACIÓN AUTOMÁTICO
	                    IF "DB2000_ED".ED[#for_i].Estado_EntradaCanal AND "DB2000_ED".ED[#for_i].Config_HabilitarRetardoAct THEN
	                        
	                        IF #Pulso1seg AND "DB2000_ED".ED[#for_i].Tiempos_TiempoAct < "DB2000_ED".ED[#for_i].Tiempos_SPTiempoAct THEN
	                            "DB2000_ED".ED[#for_i].Tiempos_TiempoAct += 1;
	                        END_IF;
	                        
	                        IF "DB2000_ED".ED[#for_i].Tiempos_TiempoAct >= "DB2000_ED".ED[#for_i].Tiempos_SPTiempoAct THEN
	                            "DB2000_ED".ED[#for_i].Estado_Activado := TRUE;
	                        END_IF;
	                        
	                    ELSIF "DB2000_ED".ED[#for_i].Estado_EntradaCanal THEN
	                        
	                        "DB2000_ED".ED[#for_i].Estado_Activado := TRUE;
	                    ELSE
	                        "DB2000_ED".ED[#for_i].Tiempos_TiempoAct := 0;
	                        
	                    END_IF;
	                    
	                    // =============================================================================
	                    //  RETARDO A LA DESACTIVACIÓN AUTOMÁTICO
	                    IF NOT "DB2000_ED".ED[#for_i].Estado_EntradaCanal AND "DB2000_ED".ED[#for_i].Config_HabilitarRetardoDes THEN
	                        
	                        IF #Pulso1seg AND "DB2000_ED".ED[#for_i].Tiempos_TiempoDes < "DB2000_ED".ED[#for_i].Tiempos_SPTiempoDes THEN
	                            "DB2000_ED".ED[#for_i].Tiempos_TiempoDes += 1;
	                        END_IF;
	                        
	                        IF "DB2000_ED".ED[#for_i].Tiempos_TiempoDes >= "DB2000_ED".ED[#for_i].Tiempos_SPTiempoDes THEN
	                            "DB2000_ED".ED[#for_i].Estado_Activado := FALSE;
	                        END_IF;
	                        
	                    ELSIF NOT "DB2000_ED".ED[#for_i].Estado_EntradaCanal THEN
	                        
	                        "DB2000_ED".ED[#for_i].Estado_Activado := FALSE;
	                        
	                    ELSE
	                        
	                        "DB2000_ED".ED[#for_i].Tiempos_TiempoDes := 0;
	                        
	                    END_IF;
	                    
	                END_IF;
	                
	            END_REGION ESTADO_DEL_DISPOSITIVO
	            
	            
	            REGION TRAZABILIDAD_MANUALIZACION
	                
	                IF "DB2000_ED".ED[#for_i].Estado_AutoMan AND NOT "DB2000_ED".ED[#for_i].Aux_oldAutoMan THEN
	                    "FC8_ZC_TRZ_REGISTRO"(FechaHora := #FechaHoraActual,
	                                            Registrar := 1,
	                                            Categoria := "TRZ_CAT_10_DISP_ED",
	                                            User := #UsuarioActual,
	                                            CodInt_1 := "TRZ_SYS_DISP_TIPO_ED",
	                                            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 "DB2000_ED".ED[#for_i].Estado_AutoMan AND "DB2000_ED".ED[#for_i].Aux_oldAutoMan THEN
	                    "FC8_ZC_TRZ_REGISTRO"(FechaHora := #FechaHoraActual,
	                                            Registrar := 1,
	                                            Categoria := "TRZ_CAT_10_DISP_ED",
	                                            User := #UsuarioActual,
	                                            CodInt_1 := "TRZ_SYS_DISP_TIPO_ED",
	                                            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 "DB2000_ED".ED[#for_i].Estado_AutoMan AND "DB2000_ED".ED[#for_i].Estado_Activado AND NOT "DB2000_ED".ED[#for_i].Aux_oldActivado THEN
	                    "FC8_ZC_TRZ_REGISTRO"(FechaHora := #FechaHoraActual,
	                                            Registrar := 1,
	                                            Categoria := "TRZ_CAT_10_DISP_ED",
	                                            User := #UsuarioActual,
	                                            CodInt_1 := "TRZ_SYS_DISP_TIPO_ED",
	                                            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 "DB2000_ED".ED[#for_i].Estado_AutoMan AND NOT "DB2000_ED".ED[#for_i].Estado_Activado AND "DB2000_ED".ED[#for_i].Aux_oldActivado THEN
	                    "FC8_ZC_TRZ_REGISTRO"(FechaHora := #FechaHoraActual,
	                                            Registrar := 1,
	                                            Categoria := "TRZ_CAT_10_DISP_ED",
	                                            User := #UsuarioActual,
	                                            CodInt_1 := "TRZ_SYS_DISP_TIPO_ED",
	                                            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 TRAZABILIDAD_MANUALIZACION
	            
	            
	            // =============================================================================
	            // ESTADO ANTERIOR MANUAL/AUTOMÁTICO
	            "DB2000_ED".ED[#for_i].Aux_oldAutoMan := "DB2000_ED".ED[#for_i].Estado_AutoMan;
	            "DB2000_ED".ED[#for_i].Aux_oldActivado := "DB2000_ED".ED[#for_i].Estado_Activado;
	            
	        ELSE
	            
	            // =============================================================================
	            // DISPOSITIVO NO HABILITADO
	            // =============================================================================
	            "DB2000_ED".ED[#for_i].Estado_EntradaCanal := FALSE;
	            "DB2000_ED".ED[#for_i].Estado_Activado := FALSE;
	            "DB2000_ED".ED[#for_i].Tiempos_TiempoAct := 0;
	            "DB2000_ED".ED[#for_i].Tiempos_TiempoDes := 0;
	            
	        END_IF;
	        
	        REGION ESTADO_HMI
	            
	            // =============================================================================
	            //  ESTADO BITS PARA VISUALIZACION
	            //  Bit     0   Habilitacion
	            //  Bit     1   ManualAutomatico
	            //  Bit     2   Enclavado
	            //  Bit     3   Activado 1
	            //  Bit     4   Activado 2
	            //  Bit     5   Reserva
	            //  Bit     6   Reserva
	            //  Bit     7   Reserva
	            //  Bit     8   Alarma General
	            //  Bit     9   Alarma 1
	            //  Bit     10  Alarma 2
	            //  Bit     11  Alarma 3
	            //  Bit     12  Alarma 4
	            //  Bit     13  Alarma Mantenimiento
	            //  Bit     14  Reserva
	            //  Bit     15  Reserva
	            "DB2000_ED".ED[#for_i].Hmi_Estado.%X0 := "DB2000_ED".ED[#for_i].Config_Habilitar;
	            "DB2000_ED".ED[#for_i].Hmi_Estado.%X1 := "DB2000_ED".ED[#for_i].Estado_AutoMan;
	            "DB2000_ED".ED[#for_i].Hmi_Estado.%X2 := FALSE;
	            "DB2000_ED".ED[#for_i].Hmi_Estado.%X3 := "DB2000_ED".ED[#for_i].Estado_Activado;
	            "DB2000_ED".ED[#for_i].Hmi_Estado.%X4 := FALSE;
	            "DB2000_ED".ED[#for_i].Hmi_Estado.%X5 := FALSE;
	            "DB2000_ED".ED[#for_i].Hmi_Estado.%X6 := FALSE;
	            "DB2000_ED".ED[#for_i].Hmi_Estado.%X7 := FALSE;
	            "DB2000_ED".ED[#for_i].Hmi_Estado.%X8 := FALSE;
	            "DB2000_ED".ED[#for_i].Hmi_Estado.%X9 := FALSE;
	            "DB2000_ED".ED[#for_i].Hmi_Estado.%X10 := FALSE;
	            "DB2000_ED".ED[#for_i].Hmi_Estado.%X11 := FALSE;
	            "DB2000_ED".ED[#for_i].Hmi_Estado.%X12 := FALSE;
	            "DB2000_ED".ED[#for_i].Hmi_Estado.%X13 := FALSE;
	            "DB2000_ED".ED[#for_i].Hmi_Estado.%X14 := FALSE;
	            "DB2000_ED".ED[#for_i].Hmi_Estado.%X15 := FALSE;
	            
	            
	        END_REGION ESTADO_HMI
	        
	    END_FOR;
	    
	END_REGION
	
END_FUNCTION

