FUNCTION_BLOCK "FB15053_ZC_INF_LIMP_MAQ"
TITLE = FB15053_ZC_INF_LIMP_MAQ
{ S7_Optimized_Access := 'TRUE' }
AUTHOR : ABH
FAMILY : ZeusControl
VERSION : 1.0
//Bloque de gestion para adquisicion de datos para informe de limpieza de maquinas
   VAR_INPUT 
      EnLimpieza : Bool;   // En limpieza
      LimpBasica1 : Bool;   // En limpieza basica 1
      LimpAcida : Bool;   // En limpieza acida
      LimpBasica2 : Bool;   // En limpieza basica 2
      Pulso1Seg : Bool;   // Pulso de 1 segundo
      FechaHoraActual {InstructionName := 'DTL'; LibVersion := '1.0'; ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : DTL;   // Fecha y hora actual
      TempBasica1 : LReal;   // Temperatura basica 1
      CTLimpBasica1 : LReal;   // Conductividad limpieza basica 1
      CTEnjBasica1 : LReal;   // Conductividad enjuague basica 1
      PorcentajeQRefBasica1 : LReal;   // Porcentaje Q Referencia basica 1
      TempAcida : LReal;   // Temperatura acida
      CTLimpAcida : LReal;   // Conductividad limpieza acida
      CTEnjAcida : LReal;   // Conductividad enjuague acida
      PorcentajeQRefAcida : LReal;   // Porcentaje Q Referencia acida
      TempBasica2 : LReal;   // Temperatura basica 2
      CTLimpBasica2 : LReal;   // Conductividad limpieza basica 2
      CTEnjBasica2 : LReal;   // Conductividad enjuague basica 2
      PorcentajeQRefBasica2 : LReal;   // Porcentaje Q Referencia basica 2
      TipoLimpieza : Int;   // Tipo de limpieza
      TiempoLimpieza : "UDT_ZC_CONTADOR_TIEMPO";   // Tiempo de limpieza
   END_VAR

   VAR_IN_OUT 
      Informe : Array[*] of "UDT_ZC_INF_LIMP_MAQ";   // Informe
   END_VAR

   VAR 
      s_OrdenInicioInforme { S7_SetPoint := 'True'} : Bool;   // Orden inicio informe
      s_OrdenFinInforme { S7_SetPoint := 'True'} : Bool;   // Orden fin informe
   END_VAR
   VAR RETAIN
      s_oldInicio { S7_SetPoint := 'True'} : Bool;   // Estado anterior inicio
      s_oldFin { S7_SetPoint := 'True'} : Bool;   // Estado anterior fin
   END_VAR
   VAR 
      s_OrdenBorrarInforme : Bool;   // Orden borrar informe
      s_NumeroBorrado : Int;   // -1= Todos / Valor= Numero de registro
   END_VAR
   VAR RETAIN
      TiempoRecircBasica1 : Int;   // Tiempo en recirculacion basica 1
      TiempoRecircAcida : Int;   // Tiempo en recirculacion acida
      TiempoRecircBasica2 : Int;   // Tiempo en recirculacion basica 2
   END_VAR

   VAR_TEMP 
      for_i : Int;
      t_dummyInt : Int;
      t_IndiceSuperior : Int;   // Indice superior del array
      t_IndiceInferior : Int;   // Indice inferior del array
      t_InformeVacio : "UDT_ZC_INF_LIMP_MAQ";
   END_VAR

   VAR CONSTANT 
      ACTUAL : Int := 1;
   END_VAR


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

