FUNCTION_BLOCK "FB15106_ZC_CALCULO_LIMP_4_MOD"
TITLE = FB15106_ZC_CALCULO_LIMP_4_MOD
{ S7_Optimized_Access := 'TRUE' }
AUTHOR : ABH
FAMILY : ZeusControl
VERSION : 1.0
//Bloque de funcion para el calculo de limpiezas modulos (4 modulos).
   VAR_INPUT 
      Etapa : Bool;   // En etapa de recirculacion
      Pulso1Seg : Bool;
      EnMarcha : Bool;
      SP_Tiempo : Int;   // Set Point tiempo de recirculacion
      SP_Salida1 : Real;   // Set Point (%) tiempo limpieza modulo 1
      SP_Salida2 : Real;   // Set Point (%) tiempo limpieza modulo 2
      SP_Salida3 : Real;   // Set Point (%) tiempo limpieza modulo 3
      SP_Salida4 : Real;   // Set Point (%) tiempo limpieza modulo 4
   END_VAR

   VAR_IN_OUT 
      EtapaTiempoRestante : Int;   // Tiempo de etapa restante
      Salida1 : Bool;   // Orden limpiar solo modulo 1
      Salida2 : Bool;   // Orden limpiar solo modulo 2
      Salida3 : Bool;   // Orden limpiar solo modulo 3
      Salida4 : Bool;   // Orden limpiar solo modulo 4
   END_VAR

   VAR RETAIN
      s_PorcentajeSalida1 { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Real;
      s_PorcentajeSalida2 { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Real;
   END_VAR
   VAR 
      s_PorcentajeSalida3 : Real;
      s_PorcentajeSalida4 : Real;
   END_VAR
   VAR RETAIN
      s_PorcentajeRestante { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Real;
      s_CalculoTiempoSalida1 { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Int;
      s_CalculoTiempoSalida2 { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Int;
   END_VAR
   VAR 
      s_CalculoTiempoSalida3 : Int;
      s_CalculoTiempoSalida4 : Int;
   END_VAR
   VAR RETAIN
      s_CalculoTiempoRestante { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Int;
      s_TiempoSalida1 { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Int;
      s_TiempoSalida2 { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Int;
   END_VAR
   VAR 
      s_TiempoSalida3 : Int;
      s_TiempoSalida4 : Int;
      S_TON { S7_SetPoint := 'False'} : "UDT_ZC_DISP_TON";
      s_TiempoTotal { S7_SetPoint := 'True'} : Int;
      s_ContadorTiempo : 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 4 módulos, asignando a cada uno un porcentaje configurable del tiempo total de la etapa. A partir de los porcentajes validados y del tiempo total, calcula los tiempos individuales de cada módulo y activa secuencialmente la salida correspondiente en función de un contador interno en segundos.
	
	Funcionalidades principales:
	- Traspaso y validación de porcentajes: se leen los porcentajes de cada uno de los 4 módulos (`SP_Salida1` a `SP_Salida4`) y se comprueba que su suma no supere `100.0`. Si la suma supera dicho umbral, se asigna por defecto un valor de seguridad de `10.0` a cada uno de los cuatro porcentajes, evitando estados incoherentes.
	- Cálculo de tiempos individuales: para cada módulo, si su porcentaje es distinto de cero, se calcula el tiempo correspondiente como `Porcentaje * SP_Tiempo / 100`, truncado a entero mediante `REAL_TO_INT`.
	- Cálculo del tiempo total: se obtiene como la suma de los cuatro tiempos calculados y se utiliza para acotar el contador interno.
	- Contador de etapa: mientras `Etapa` está activa, `EnMarcha` esté activado y `Pulso1Seg` genere un pulso por segundo, se incrementa el contador `#s_ContadorTiempo` hasta alcanzar `#s_TiempoTotal`, momento en el que se reinicia a `0` para comenzar un nuevo ciclo.
	- Activación secuencial de salidas: cada salida (`Salida1`, `Salida2`, `Salida3`, `Salida4`) se activa cuando el contador se encuentra en el intervalo de tiempo correspondiente a su módulo. `Salida4` se activa por descarte cuando ninguna de las tres anteriores está activa.
	- Reset al salir de etapa: cuando `Etapa` se desactiva, el contador y todas las salidas se ponen a cero.
	- Cálculo del tiempo restante de etapa (`EtapaTiempoRestante`): se calcula en función de la salida activa como la diferencia entre el tiempo acumulado del módulo y el contador actual. Si el resultado es negativo, se satura a `0`.
	
	> **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 | (HCR)   | Primera versión. |
	*)
	END_REGION DESCRIPCION
	
	
	//  ==========================================================================================================
	REGION TRASPASO_PARAMETROS
	    
	    //  =====================================================================================
	    //  TRASPASO DE PARAMETROS DE PORCENTAJE
	    //  Se revisa los limites de los porcentajes metidos en pantalla
	    IF (#SP_Salida1 + #SP_Salida2 + #SP_Salida3 + #SP_Salida4) > 100.0 THEN
	        #s_PorcentajeSalida1 := 10.0;
	        #s_PorcentajeSalida2 := 10.0;
	        #s_PorcentajeSalida3 := 10.0;
	        #s_PorcentajeSalida4 := 10.0;
	    ELSE
	        #s_PorcentajeSalida1 := #SP_Salida1;
	        #s_PorcentajeSalida2 := #SP_Salida2;
	        #s_PorcentajeSalida3 := #SP_Salida3;
	        #s_PorcentajeSalida4 := #SP_Salida4;
	    END_IF;
	    
	    
	END_REGION
	
	
	//  ==========================================================================================================
	REGION CALCULOS
	    
	    //  =====================================================================================
	    //  CALCULO DE TIEMPO DE PASO
	    //  MODULO 1
	    IF #s_PorcentajeSalida1 <> 0.0 THEN
	        #s_CalculoTiempoSalida1 := REAL_TO_INT((#s_PorcentajeSalida1 * #SP_Tiempo) / 100.0);
	    END_IF;
	    
	    //  MODULO 2
	    IF #s_PorcentajeSalida2 <> 0.0 THEN
	        #s_CalculoTiempoSalida2 := REAL_TO_INT((#s_PorcentajeSalida2 * #SP_Tiempo) / 100.0);
	    END_IF;
	    
	    //  MODULO 3
	    IF #s_PorcentajeSalida3 <> 0.0 THEN
	        #s_CalculoTiempoSalida3 := REAL_TO_INT((#s_PorcentajeSalida3 * #SP_Tiempo) / 100.0);
	    END_IF;
	    
	    //  MODULO 4
	    IF #s_PorcentajeSalida4 <> 0.0 THEN
	        #s_CalculoTiempoSalida4 := REAL_TO_INT((#s_PorcentajeSalida4 * #SP_Tiempo) / 100.0);
	    END_IF;
	    
	    #s_TiempoTotal := #s_CalculoTiempoSalida1 + #s_CalculoTiempoSalida2 + #s_CalculoTiempoSalida3 + #s_CalculoTiempoSalida4;
	    
	END_REGION
	
	
	//  ==========================================================================================================
	REGION SALIDAS
	    IF #Etapa THEN
	        
	        IF #s_ContadorTiempo < #s_TiempoTotal THEN
	            IF #Pulso1Seg AND #EnMarcha THEN
	                #s_ContadorTiempo += 1;
	            END_IF;
	        ELSE
	            #s_ContadorTiempo := 0;
	        END_IF;
	        
	        //  ACTIVACION 1
	        IF #s_ContadorTiempo < #s_CalculoTiempoSalida1 AND #s_CalculoTiempoSalida1 <> 0 THEN
	            #Salida1 := TRUE;
	        ELSE
	            #Salida1 := FALSE;
	        END_IF;
	        
	        //  ACTIVACION 2
	        IF #s_ContadorTiempo >= #s_CalculoTiempoSalida1 AND #s_ContadorTiempo < (#s_CalculoTiempoSalida2 + #s_CalculoTiempoSalida1) AND #s_CalculoTiempoSalida2 <> 0 THEN
	            #Salida2 := TRUE;
	        ELSE
	            #Salida2 := FALSE;
	        END_IF;
	        
	        //  ACTIVACION FLIP 3
	        IF #s_ContadorTiempo >= (#s_CalculoTiempoSalida2 + #s_CalculoTiempoSalida1) AND #s_ContadorTiempo < (#s_CalculoTiempoSalida2 + #s_CalculoTiempoSalida1 + #s_CalculoTiempoSalida3) AND #s_ContadorTiempo <> 0 THEN
	            #Salida3 := TRUE;
	        ELSE
	            #Salida3 := FALSE;
	        END_IF;
	        
	        //  ACTIVACION FLIP 4
	        #Salida4 := NOT #Salida1 AND NOT #Salida2 AND NOT #Salida3;
	        
	    ELSE
	        #s_ContadorTiempo := 0;
	        #Salida1 := FALSE;
	        #Salida2 := FALSE;
	        #Salida3 := FALSE;
	        #Salida4 := FALSE;
	    END_IF;
	    
	    //  ACTIVACION 1
	    IF #s_ContadorTiempo < #s_CalculoTiempoSalida1 AND #s_CalculoTiempoSalida1 <> 0 THEN
	        #Salida1 := TRUE;
	    ELSE
	        #Salida1 := FALSE;
	    END_IF;
	    
	    //  ACTIVACION 2
	    IF #s_ContadorTiempo >= #s_CalculoTiempoSalida1 AND #s_ContadorTiempo < (#s_CalculoTiempoSalida2 + #s_CalculoTiempoSalida1) AND #s_CalculoTiempoSalida2 <> 0 THEN
	        #Salida2 := TRUE;
	    ELSE
	        #Salida2 := FALSE;
	    END_IF;
	    
	    //  ACTIVACION FLIP 3
	    IF #s_ContadorTiempo >= (#s_CalculoTiempoSalida2 + #s_CalculoTiempoSalida1) AND #s_ContadorTiempo < (#s_CalculoTiempoSalida2 + #s_CalculoTiempoSalida1 + #s_CalculoTiempoSalida3) AND #s_ContadorTiempo <> 0 THEN
	        #Salida3 := TRUE;
	    ELSE
	        #Salida3 := FALSE;
	    END_IF;
	    
	    //  ACTIVACION FLIP 4
	    #Salida4 := NOT #Salida1 AND NOT #Salida2 AND NOT #Salida3;
	    
	    IF NOT #Etapa THEN
	        #Salida1 := #Salida2 := #Salida3 := #Salida4 := FALSE;
	    END_IF;
	    
	END_REGION
	
	
	//  ==========================================================================================================
	REGION TIEMPO RESTANTE
	    IF #Salida1 THEN
	        #EtapaTiempoRestante := #s_CalculoTiempoSalida1 - #s_ContadorTiempo;
	    END_IF;
	    IF #Salida2 THEN
	        #EtapaTiempoRestante := (#s_CalculoTiempoSalida1 + #s_CalculoTiempoSalida2) - #s_ContadorTiempo;
	    END_IF;
	    IF #Salida3 THEN
	        #EtapaTiempoRestante := (#s_CalculoTiempoSalida1 + #s_CalculoTiempoSalida2 + #s_CalculoTiempoSalida3) - #s_ContadorTiempo;
	    END_IF;
	    IF #Salida4 THEN
	        #EtapaTiempoRestante := #s_TiempoTotal - #s_ContadorTiempo;
	    END_IF;
	    
	    IF #EtapaTiempoRestante < 0 THEN
	        #EtapaTiempoRestante := 0;
	    END_IF;
	    
	END_REGION
	
END_FUNCTION_BLOCK

