FUNCTION_BLOCK "FB15104_ZC_CALCULO_LIMP_2_MOD"
TITLE = FB15104_ZC_CALCULO_LIMP_2_MOD
{ S7_Optimized_Access := 'TRUE' }
AUTHOR : ABH
FAMILY : ZeusControl
VERSION : 1.0
//Bloque de funcion para el calculo de limpiezas modulos (2 modulos).
   VAR_INPUT 
      EtapaRecirculacion : Bool;   // En etapa de recirculacion
      EtapaTiempoRestante : Int;   // Tiempo de etapa restante
      SP_TiempoRecirculacion : Int;   // Set Point tiempo de recirculacion
      SP_Modulo1 : Real;   // Set Point (%) tiempo limpieza modulo 1
      SP_Modulo2 : Real;   // Set Point (%) tiempo limpieza modulo 2
   END_VAR

   VAR_OUTPUT 
      LimpiarSoloModulo1 : Bool;   // Orden limpiar solo modulo 1
      LimpiarSoloModulo2 : Bool;   // Orden limpiar solo modulo 2
      LimpiarTodosLosModulos : Bool;   // Orden limpiar todos los modulos.
   END_VAR

   VAR RETAIN
      s_PorcentajeMinimoTodosModulos { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Real := 20.0;   // Set Point (%) minimo para limpieza de todos los modulos
      s_PorcentajeModulo1 { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Real;
      s_PorcentajeModulo2 { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Real;
      s_PorcentajeRestante { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Real;
      s_CalculoTiempoModulo1 { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Int;
      s_CalculoTiempoModulo2 { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Int;
      s_CalculoTiempoRestante { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Int;
      s_TiempoModulo1 { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Int;
      s_TiempoModulo2 { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Int;
   END_VAR


BEGIN
	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 funcion que implementa el cálculo y la distribución temporal de la limpieza de 2 módulos de membranas, con soporte operativo para 3 módulos mediante la agrupación de los módulos 2 y 3 en una sola fase. Permite configurar, en porcentaje, el peso de cada módulo dentro del tiempo total de recirculación y reparte el tiempo restante a una fase conjunta de limpieza de todos los módulos.
	
	Funcionalidades principales:
	- Traspaso y validación de porcentajes: se leen los porcentajes de cada módulo (`SP_Modulo1`, `SP_Modulo2`) y se limitan para que la suma no supere el máximo disponible (`100 - s_PorcentajeMinimoTodosModulos`). Si la suma supera dicho umbral, ambos porcentajes se igualan al valor medio permitido, garantizando que siempre quede un mínimo reservado para la fase de limpieza conjunta. El porcentaje restante (`s_PorcentajeRestante`) se calcula como `100 - (s_PorcentajeModulo1 + s_PorcentajeModulo2)`.
	- Cálculo de tiempos: a partir del tiempo total de recirculación (`SP_TiempoRecirculacion`) y de los porcentajes validados, se obtienen los tiempos individuales de cada módulo (`s_CalculoTiempoModulo1`, `s_CalculoTiempoModulo2`) y el tiempo restante (`s_CalculoTiempoRestante`). Se calculan también los tiempos acumulados hasta el inicio de cada fase (`s_TiempoModulo1`, `s_TiempoModulo2`) para acotar la salida de la etapa en curso.
	- Activación de salidas de limpieza: durante la etapa de recirculación (`EtapaRecirculacion`), en función del valor de `EtapaTiempoRestante`, se activa la salida correspondiente:
	    - `LimpiarSoloModulo1`: mientras el tiempo restante está comprendido entre `s_TiempoModulo1` y `SP_TiempoRecirculacion` y el porcentaje del módulo 1 es distinto de cero.
	    - `LimpiarSoloModulo2`: mientras el tiempo restante está comprendido entre `s_TiempoModulo2` y `s_TiempoModulo1` y el porcentaje del módulo 2 es distinto de cero.
	    - `LimpiarTodosLosModulos`: en el resto de casos, durante la fase final del tiempo de recirculación.
	- Las salidas son mutuamente excluyentes: en todo momento solo una de las tres se encuentra activa, inicializándose todas a `FALSE` al inicio de la región.
	
	> **Restricciones:** Ninguna.
	
	---
	### Dependencias Requeridas
	| Tipo | Elementos |
	|------|-----------|
	| FC   | - |
	| FB   | - |
	| DB   | - |
	| UDT  | - |
	    
	---
	### Historial de Cambios
	| Versión  | Fecha      | Técnico | Cambios |
	|----------|------------|---------|---------|
	| 01.00.00 | 12.09.2023 | (ABH)   | Primera versión. |
	| 01.00.01 | 17.11.2023 | (HCR/ABH) | Cambio en nombre de parámetro de entrada `EtapaTiempoActual` por `EtapaTiempoRestante`. Se añade parámetro estático `s_PorcentajeMinimoTodosModulos` para límite de los SP de porcentaje de tiempo de cada módulo para no sobrepasar el 100% del tiempo. |
	*)
	END_REGION DESCRIPCION
	
	
	//  ==========================================================================================================
	REGION TRASPASO_PARAMETROS
	    
	    //  =====================================================================================
	    //  TRASPASO DE PARAMETROS DE PORCENTAJE
	    //  Se revisa los limites de los porcentajes metidos en pantalla
	    IF (#SP_Modulo1 + #SP_Modulo2) > (100.0 - #s_PorcentajeMinimoTodosModulos) THEN
	        #s_PorcentajeModulo1 := ((100.0 - #s_PorcentajeMinimoTodosModulos) / 2.0);
	        #s_PorcentajeModulo2 := #s_PorcentajeModulo1;
	    ELSE
	        #s_PorcentajeModulo1 := #SP_Modulo1;
	        #s_PorcentajeModulo2 := #SP_Modulo2;
	    END_IF;
	    #s_PorcentajeRestante := 100.0 - (#s_PorcentajeModulo1 + #s_PorcentajeModulo2);
	    
	END_REGION
	
	
	//  ==========================================================================================================
	REGION CALCULOS
	    
	    //  =====================================================================================
	    //  CALCULO DE TIEMPO DE PASO
	    //  MODULO 1
	    IF #s_PorcentajeModulo1 <> 0.0 THEN
	        #s_CalculoTiempoModulo1 := REAL_TO_INT((#s_PorcentajeModulo1 * #SP_TiempoRecirculacion) / 100.0);
	    END_IF;
	    
	    //  MODULO 2 y 3
	    IF #s_PorcentajeModulo2 <> 0.0 THEN
	        #s_CalculoTiempoModulo2 := REAL_TO_INT((#s_PorcentajeModulo2 * #SP_TiempoRecirculacion) / 100.0);
	    END_IF;
	    
	    //  TIEMPO RESTANTE
	    #s_CalculoTiempoRestante := #SP_TiempoRecirculacion - (#s_CalculoTiempoModulo1 + #s_CalculoTiempoModulo2);
	    
	    
	    #s_TiempoModulo1 := #SP_TiempoRecirculacion - #s_CalculoTiempoModulo1;
	    #s_TiempoModulo2 := #SP_TiempoRecirculacion - #s_CalculoTiempoModulo1 - #s_CalculoTiempoModulo2;
	    
	END_REGION
	
	
	//  ==========================================================================================================
	REGION SALIDAS
	    
	    #LimpiarSoloModulo1 := #LimpiarSoloModulo2 := #LimpiarTodosLosModulos := FALSE;
	    
	    IF #EtapaRecirculacion THEN
	        
	        IF (#s_PorcentajeModulo1 <> 0.0) AND #EtapaTiempoRestante <= #SP_TiempoRecirculacion AND #EtapaTiempoRestante > #s_TiempoModulo1 THEN
	            #LimpiarSoloModulo1 := TRUE;
	            #LimpiarSoloModulo2 := #LimpiarTodosLosModulos := FALSE;
	        ELSIF (#s_PorcentajeModulo2 <> 0.0) AND #EtapaTiempoRestante <= #s_TiempoModulo1 AND #EtapaTiempoRestante > #s_TiempoModulo2 THEN
	            #LimpiarSoloModulo2 := TRUE;
	            #LimpiarSoloModulo1 := #LimpiarTodosLosModulos := FALSE;
	        ELSE
	            #LimpiarTodosLosModulos := TRUE;
	            #LimpiarSoloModulo1 := #LimpiarSoloModulo2 := FALSE;
	        END_IF;
	        
	    END_IF;
	    
	END_REGION
	
	
END_FUNCTION_BLOCK

