FUNCTION_BLOCK "FB15057_ZC_CONT_PROD_MEM"
TITLE = FB15057_ZC_CONT_PROD_MEM
{ S7_Optimized_Access := 'TRUE' }
AUTHOR : ABH
FAMILY : ZeusControl
VERSION : 1.0
//Bloque de funcion para gestion de contadores de produccion maquinas membranas
   VAR_INPUT 
      InicioProduccion : Bool;   // En etapa inicio produccion
      EnProduccion : Bool;   // En etapas de produccion
      FinProduccion : Bool;   // En etapa fin de produccion
      FechaHoraActual {InstructionName := 'DTL'; LibVersion := '1.0'; ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : DTL;   // Fecha y hora actual
      LitrosEntrada : LReal;   // Totalizador litros entrada
      LitrosConcentrado : LReal;   // Totalizador litros concentrado
      LitrosPermeado : LReal;   // Totalizador litros permeado
      FCV : Real;   // Factor de concentradion
      Brix : LReal;   // Media de grados BRIX
      TempAlimentacion : LReal;   // Temperatura alimentacion
      TempConcentrado : LReal;   // Temperatura Concentrado
      TempPermeado : LReal;   // Temperatura Permeado
      BorrarParcial : Bool;   // Borrar datos parciales
   END_VAR

   VAR RETAIN
      Ultima { S7_SetPoint := 'False'} : "UDT_ZC_CONT_PROD_MEM";
      Penultima { S7_SetPoint := 'False'} : "UDT_ZC_CONT_PROD_MEM";
      Parcial { S7_SetPoint := 'False'} : "UDT_ZC_CONT_PROD_MEM";
      Total { S7_SetPoint := 'False'} : "UDT_ZC_CONT_PROD_MEM";
   END_VAR
   VAR 
      s_OldInicioProd { S7_SetPoint := 'True'} : Bool;
      s_OldFinProd { S7_SetPoint := 'True'} : Bool;
      s_InicioProduccion : Bool;   // Orden inicio produccion
      s_FinProduccion : Bool;   // Orden fin de produccion
   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 la gestión de los contadores y totalizadores de producción de una máquina de membranas, manteniendo la trazabilidad histórica de la última y penúltima producción, así como los acumulados parciales y totales, junto con el cálculo del factor de conversión volumétrica (FCV) asociado a cada periodo.
	
	Funcionalidades principales:
	- Detección de flanco ascendente en las órdenes `#InicioProduccion` y `#FinProduccion` mediante las variables estáticas `#s_P_Trig_InicioProd` y `#s_P_Trig_FinProd`, generando los pulsos internos `#s_InicioProduccion` y `#s_FinProduccion` para evitar disparos múltiples por nivel mantenido.
	- Inicio de producción: al recibir `#s_InicioProduccion` se trasladan los datos de la última producción a la estructura `#Penultima`, se inicializan a cero los campos analíticos y de fecha de `#Ultima`, y se registra la fecha/hora de inicio en `#Ultima.FechaInicio` mediante la conversión realizada por `FC15005_ZC_DTL_TO_ZC_FECHA`.
	- Datos en curso: mientras `#EnProduccion` está activo, se copian en `#Ultima` las variables de proceso (`LitrosEntrada`, `LitrosConcentrado`, `Brix`, `TempAlimentacion`, `TempConcentrado`, `TempPermeado`), manteniendo actualizada la instantánea de la producción en marcha.
	- Fin de producción: al detectar `#s_FinProduccion` se registra la fecha/hora de fin en `#Ultima.FechaFin` y se acumulan los valores de la producción actual sobre los contadores `#Parcial` y `#Total`, tanto de litros de entrada como de concentrado.
	- Cálculo de litros de permeado por diferencia (`LitrosEntrada - LitrosConcentrado`) para las cuatro estructuras: `#Ultima`, `#Penultima`, `#Parcial` y `#Total`.
	- Cálculo del factor de conversión volumétrica (FCV) para cada estructura con protección frente a división por cero (cuando `#LitrosEntrada` o `#LitrosConcentrado` son menores o iguales a `0.0`, el resultado se fija en `0.0`).
	- Reset de la producción parcial: la entrada `#BorrarParcial` reinicia los litros del contador parcial y actualiza `#Parcial.FechaInicio` con la fecha/hora actual.
	
	> **Restricciones:** Ninguna.
	
	---
	### Dependencias Requeridas
	| Tipo | Elementos |
	|------|-----------|
	| FC   | `FC15005_ZC_DTL_TO_ZC_FECHA` |
	| FB   | - |
	| DB   | - |
	| UDT  | `UDT_ZC_CONTADORES_PRODUCCION` |
	    
	---
	### Historial de Cambios
	| Versión  | Fecha      | Técnico | Cambios |
	|----------|------------|---------|---------|
	| 01.00.00 | 29.09.2023 | (ABH)   | Primera versión. |
	| 01.00.01 | 04.03.2024 | (ABH)   | Se corrige gestión de marca fin de producción. |
	| 01.00.02 | 03.07.2026 | (ABH)   | Cambio a SCL. |
	*)
	END_REGION DESCRIPCION
	
	
	//  ==========================================================================================================
	REGION GESTION_ORDENES
	    
	    //  Inicio de produccion
	    #s_InicioProduccion := #InicioProduccion AND NOT #s_OldInicioProd;
	    
	    //  Fin de produccion
	    #s_FinProduccion := #FinProduccion AND NOT #s_OldFinProd;
	    
	    //  Estados anteriores
	    #s_OldInicioProd := #InicioProduccion;
	    #s_OldFinProd := #FinProduccion;
	    
	END_REGION GESTION_ORDENES
	
	
	//  ==========================================================================================================
	REGION MOVIMIENTO_DE_DATOS
	    
	    //  ==========================================================================================================
	    REGION INICIO_PRODUCCION
	        
	        IF #s_InicioProduccion THEN
	            
	            //  =================================================================================================
	            //  Traspaso de datos de ultima produccion a penultima produccion
	            #Penultima.LitrosEntrada := #Ultima.LitrosEntrada;
	            #Penultima.LitrosConcentrado := #Ultima.LitrosConcentrado;
	            #Penultima.Brix := #Ultima.Brix;
	            #Penultima.TempAlimentacion := #Ultima.TempAlimentacion;
	            #Penultima.TempConcentrado := #Ultima.TempConcentrado;
	            #Penultima.FechaInicio := #Ultima.FechaInicio;
	            #Penultima.FechaFin := #Ultima.FechaFin;
	            
	            
	            //  =================================================================================================
	            //  Reset datos ultima produccion
	            #Ultima.LitrosEntrada := 0.0;
	            #Ultima.LitrosConcentrado := 0.0;
	            #Ultima.Brix := 0.0;
	            #Ultima.TempAlimentacion := 0.0;
	            #Ultima.TempConcentrado := 0.0;
	            #Ultima.FechaInicio.Ano := 0;
	            #Ultima.FechaInicio.Mes := 0;
	            #Ultima.FechaInicio.Dia := 0;
	            #Ultima.FechaInicio.Hora := 0;
	            #Ultima.FechaInicio.Minuto := 0;
	            #Ultima.FechaInicio.Segundo := 0;
	            #Ultima.FechaFin.Ano := 0;
	            #Ultima.FechaFin.Mes := 0;
	            #Ultima.FechaFin.Dia := 0;
	            #Ultima.FechaFin.Hora := 0;
	            #Ultima.FechaFin.Minuto := 0;
	            #Ultima.FechaFin.Segundo := 0;
	            
	            
	            //  =================================================================================================
	            //  Guardamos la fecha y hora de inicio de la produccion
	            #Ultima.FechaInicio := "FC15005_ZC_DTL_TO_ZC_FECHA"(#FechaHoraActual);
	            
	        END_IF;
	        
	    END_REGION INICIO_PRODUCCION
	    
	    
	    //  ==========================================================================================================
	    REGION DATOS_DURANTE_PRODUCCION
	        
	        //  Movimientos de datos durante la produccion
	        IF #EnProduccion THEN
	            
	            #Ultima.LitrosEntrada := #LitrosEntrada;
	            #Ultima.LitrosConcentrado := #LitrosConcentrado;
	            #Ultima.Brix := #Brix;
	            #Ultima.TempAlimentacion := #TempAlimentacion;
	            #Ultima.TempConcentrado := #TempConcentrado;
	            #Ultima.TempPermeado := #TempPermeado;
	        END_IF;
	        
	    END_REGION DATOS_DURANTE_PRODUCCION
	    
	    
	    //  ==========================================================================================================
	    REGION DATOS_AL_FIN_PRODUCCION
	        
	        //  Movimiento de datos al finalizar la produccion
	        IF #s_FinProduccion THEN
	            
	            //  Fecha fin
	            #Ultima.FechaFin := "FC15005_ZC_DTL_TO_ZC_FECHA"(#FechaHoraActual);
	            
	            //  Suma de datos parciales y totales
	            #Parcial.LitrosEntrada := #Ultima.LitrosEntrada + #Parcial.LitrosEntrada;
	            #Parcial.LitrosConcentrado := #Ultima.LitrosConcentrado + #Parcial.LitrosConcentrado;
	            #Total.LitrosEntrada := #Ultima.LitrosEntrada + #Total.LitrosEntrada;
	            #Total.LitrosConcentrado := #Ultima.LitrosConcentrado + #Total.LitrosConcentrado;
	            
	        END_IF;
	        
	    END_REGION DATOS_AL_FIN_PRODUCCION
	    
	    
	    
	END_REGION MOVIMIENTO_DE_DATOS
	
	
	//  ==========================================================================================================
	REGION CALCULOS
	    
	    
	    //  ==========================================================================================================
	    REGION TOTALIZADORES                
	        
	        //  Ultima produccion
	        #Ultima.LitrosPermeado := #Ultima.LitrosEntrada - #Ultima.LitrosConcentrado;
	        
	        //  Penultima produccion
	        #Penultima.LitrosPermeado := #Penultima.LitrosEntrada - #Penultima.LitrosConcentrado;
	        
	        //  Produccion parcial
	        #Parcial.LitrosPermeado := #Parcial.LitrosEntrada - #Parcial.LitrosConcentrado;
	        
	        //  Produccion total
	        #Total.LitrosPermeado := #Total.LitrosEntrada - #Total.LitrosConcentrado;
	        
	    END_REGION TOTALIZADORES
	    
	    
	    //  ==========================================================================================================
	    REGION FCV
	        
	        //  FCV Ultima produccion
	        IF #Ultima.LitrosEntrada > 0.0 AND #Ultima.LitrosConcentrado > 0.0 THEN
	            #Ultima.FCV := LREAL_TO_REAL(#Ultima.LitrosEntrada / #Ultima.LitrosConcentrado);
	        ELSE
	            #Ultima.FCV := 0.0;
	        END_IF;
	        
	        //  FCV Penultima produccion
	        IF #Penultima.LitrosEntrada > 0.0 AND #Penultima.LitrosConcentrado > 0.0 THEN
	            #Penultima.FCV := LREAL_TO_REAL(#Penultima.LitrosEntrada / #Penultima.LitrosConcentrado);
	        ELSE
	            #Penultima.FCV := 0.0;
	        END_IF;
	        
	        //  FCV Produccion parcial
	        IF #Parcial.LitrosEntrada > 0.0 AND #Parcial.LitrosConcentrado > 0.0 THEN
	            #Parcial.FCV := LREAL_TO_REAL(#Parcial.LitrosEntrada / #Parcial.LitrosConcentrado);
	        ELSE
	            #Parcial.FCV := 0.0;
	        END_IF;
	        
	        //  FCV Produccion Total
	        IF #Total.LitrosEntrada > 0.0 AND #Total.LitrosConcentrado > 0.0 THEN
	            #Total.FCV := LREAL_TO_REAL(#Total.LitrosEntrada / #Total.LitrosConcentrado);
	        ELSE
	            #Total.FCV := 0.0;
	        END_IF;
	        
	    END_REGION FCV
	    
	END_REGION CALCULOS
	
	
	//  ==========================================================================================================
	REGION RESET_DATOS
	    
	    //  Reset produccion parcial
	    IF #BorrarParcial THEN
	        #Parcial.LitrosEntrada := 0.0;
	        #Parcial.LitrosConcentrado := 0.0;
	        #Parcial.FechaInicio := "FC15005_ZC_DTL_TO_ZC_FECHA"(#FechaHoraActual);
	    END_IF;
	    
	END_REGION RESET_DATOS
	
END_FUNCTION_BLOCK

