FUNCTION_BLOCK "FB15200_ZC_SYNC_RECETA_PANEL"
TITLE = FB15200_ZC_SYNC_RECETA_PANEL
{ S7_Optimized_Access := 'TRUE' }
AUTHOR : ABH
FAMILY : ZeusControl
VERSION : 1.0
//Sincronizacion de recetas desde Scada (BBDD) a paneles
   VAR_INPUT 
      HabilitarBorrado : Bool := FALSE;   // Habilita el borrado de ficheros
      RutaCarpetaRecetas { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : String[25] := '\temp\RecetasScada\';
      FechaHoraActual {InstructionName := 'DTL'; LibVersion := '1.0'} : DTL;
      TiempoRetardoInicio : Time := T#20s;
      TiempoRetardoHmi : Time := T#10s;
      TiempoComprobacion : Time := T#500ms;
      TiempoError : Time := T#8s;
   END_VAR

   VAR_OUTPUT RETAIN
      ErrorImportar : Bool;
      ErrorBorrar : Bool;
   END_VAR

   VAR RETAIN
      s_ExisteRecetaNueva : Bool;
      s_OrdenSincHMI : Bool;
      s_OrdenBorrarHMI : Bool;
      s_EstadoImportar : Int;
      s_EstadoBorrar : Int;
      s_RutaCarpeta : String;
      s_Iniciar { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Bool;
      s_Etapa { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Int;
      s_EtapaSiguiente { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Int;
      UltimaSincronizacion {InstructionName := 'DTL'; LibVersion := '1.0'; S7_SetPoint := 'True'} : DTL;
   END_VAR
   VAR 
      TON_OrdenInicio {InstructionName := 'TON_TIME'; LibVersion := '1.0'; ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : TON_TIME;
      TON_RetardoImportarHmi {InstructionName := 'TON_TIME'; LibVersion := '1.0'} : TON_TIME;
      TON_RetardoBorrarHmi {InstructionName := 'TON_TIME'; LibVersion := '1.0'} : TON_TIME;
      TON_EstadoImportar {InstructionName := 'TON_TIME'; LibVersion := '1.0'; ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'; S7_SetPoint := 'False'} : TON_TIME;
      TON_ErrorImportar {InstructionName := 'TON_TIME'; LibVersion := '1.0'} : TON_TIME;
      TON_EstadoBorrar {InstructionName := 'TON_TIME'; LibVersion := '1.0'} : TON_TIME;
      TON_ErrorBorrar {InstructionName := 'TON_TIME'; LibVersion := '1.0'} : TON_TIME;
   END_VAR

   VAR CONSTANT 
      ETAPA_0_REPOSO : Int := 0;
      ETAPA_10_IMPORTAR_ORDEN_HMI : Int := 10;
      ETAPA_20_IMPORTAR_ESPERA_HMI : Int := 20;
      ETAPA_30_IMPORTAR_COMPROBACION : Int := 30;
      ETAPA_40_BORRAR_ORDEN_HMI : Int := 40;
      ETAPA_50_BORRAR_ESPERA_HMI : Int := 50;
      ETAPA_60_BORRAR_COMPROBACION : Int := 60;
   END_VAR


BEGIN
	REGION DESCRIPCION
	(*
	//=======================================================================
	// (C)Copyright ZeusControl 2022 - 2022
	//=======================================================================
	
	### Información del Sistema
	| Hardware Compatible | Entorno de Ingeniería |
	|---------------------|-----------------------|
	| PLC serie 1200/1500 | TIA Portal 18         |
	  
	---
	### Descripción Funcional
	Función central para la gestión de la sincronización de recetas con el HMI. Implementa una máquina de estados que coordina la importación (y borrado opcional) de recetas desde el HMI, gestionando las temporizaciones de espera, las señales de confirmación y los códigos de estado/error, así como el registro de la última sincronización correcta.
	
	> **Restricciones:** Ninguna.
	
	Acciones detalladas:
	- Gestiona los temporizadores generales del bloque: retardo de inicio (`TON_OrdenInicio`), retardos de orden de importar/borrar desde HMI (`TON_RetardoImportarHmi`, `TON_RetardoBorrarHmi`), temporizadores de espera de estado (`TON_EstadoImportar`, `TON_EstadoBorrar`) y temporizadores de error (`TON_ErrorImportar`, `TON_ErrorBorrar`).
	- Estado `ETAPA_0_REPOSO`: si existe receta nueva (`s_ExisteRecetaNueva`) y la etapa actual es reposo, arranca la temporización de inicio. Una vez cumplido el tiempo, se activa `s_Iniciar`, se inicializan los estados de importar/borrar, se carga la `RutaCarpetaRecetas` en `s_RutaCarpeta` y se pasa a la etapa de orden de importar al HMI.
	- Estado `ETAPA_10_IMPORTAR_ORDEN_HMI`: activa la marca `s_OrdenSincHMI` cuando se recibe desde HMI o cuando expira `TON_RetardoImportarHmi`, y transiciona a la etapa de espera de importación.
	- Estado `ETAPA_20_IMPORTAR_ESPERA_HMI`: espera a que finalice la temporización de estado (`TON_EstadoImportar`) o de error (`TON_ErrorImportar`) para pasar a la etapa de comprobación.
	- Estado `ETAPA_30_IMPORTAR_COMPROBACION`: evalúa el código de estado de importación (`s_EstadoImportar`). Si es correcto (`4`), resetea `s_ExisteRecetaNueva` y `ErrorImportar`, registra la `UltimaSincronizacion` y, si está habilitado el borrado (`HabilitarBorrado`), continúa con la etapa de borrado; en caso contrario, vuelve a `ETAPA_0_REPOSO`. Si el estado no es correcto, marca `ErrorImportar` y vuelve a reposo.
	- Estado `ETAPA_40_BORRAR_ORDEN_HMI`: activa `s_OrdenBorrarHMI` cuando se recibe desde HMI o cuando expira `TON_RetardoBorrarHmi`, y transiciona a la etapa de espera de borrado.
	- Estado `ETAPA_50_BORRAR_ESPERA_HMI`: espera a que finalice la temporización de estado (`TON_EstadoBorrar`) o de error (`TON_ErrorBorrar`) para pasar a la etapa de comprobación de borrado.
	- Estado `ETAPA_60_BORRAR_COMPROBACION`: evalúa el código de estado de borrado (`s_EstadoBorrar`). Si es correcto (`4`), resetea `s_ExisteRecetaNueva` y `ErrorBorrar`; si no, activa `ErrorBorrar`. En ambos casos, resetea los flags de estado y orden y vuelve a `ETAPA_0_REPOSO`.
	- En cada ciclo se actualiza la etapa en curso (`s_Etapa := s_EtapaSiguiente`), manteniendo la coherencia de la máquina de estados.
	
	---
	### Dependencias Requeridas
	| Tipo | Elementos |
	|------|-----------|
	| FC   | - |
	| FB   | - |
	| DB   | - |
	| UDT  | - |
	
	---
	### Historial de Cambios
	| Versión  | Fecha      | Técnico | Cambios |
	|----------|------------|---------|---------|
	| 01.00.00 | 03.11.2022 | (ABH)   | Primera versión. |
	*)
	END_REGION DESCRIPCION
	
	
	//  ==========================================================================================================
	REGION GESTION_TEMPORIZADORES
	    
	    //  Retardo inicio sincronizacion
	    #TON_OrdenInicio(IN := #s_ExisteRecetaNueva AND (#s_Etapa = #ETAPA_0_REPOSO),
	                     PT := #TiempoRetardoInicio);
	    IF #TON_OrdenInicio.Q THEN
	        #s_Iniciar := true;
	    END_IF;
	    
	    //  Retardo orden importar hmi
	    #TON_RetardoImportarHmi(IN := (#s_Etapa = #ETAPA_10_IMPORTAR_ORDEN_HMI),
	                            PT := #TiempoRetardoHmi);
	    
	    //  Retardo estado/error importar
	    #TON_EstadoImportar(IN := (#s_Etapa = #ETAPA_20_IMPORTAR_ESPERA_HMI) AND ((#s_EstadoImportar = 4) OR (#s_EstadoImportar = 12)),
	                        PT := #TiempoComprobacion);
	    #TON_ErrorImportar(IN := (#s_Etapa = #ETAPA_20_IMPORTAR_ESPERA_HMI),
	                       PT := #TiempoError);
	    
	    //  Retardo orden borrar hmi
	    #TON_RetardoBorrarHmi(IN := (#s_Etapa = #ETAPA_40_BORRAR_ORDEN_HMI),
	                          PT := #TiempoRetardoHmi);
	    
	    //  Retardo borrar estado
	    #TON_EstadoBorrar(IN := (#s_Etapa = #ETAPA_50_BORRAR_ESPERA_HMI) AND ((#s_EstadoImportar = 4) OR (#s_EstadoImportar = 12)),
	                      PT := #TiempoComprobacion);
	    #TON_ErrorBorrar(IN := (#s_Etapa = #ETAPA_50_BORRAR_ESPERA_HMI),
	                     PT := #TiempoError);
	    
	END_REGION GESTION_TEMPORIZADORES
	
	
	//  ==========================================================================================================
	REGION LOGICA
	    
	    CASE #s_Etapa OF
	            
	        #ETAPA_0_REPOSO:
	            #s_RutaCarpeta := '';
	            REGION REPOSO
	                
	                IF #s_Iniciar THEN
	                    #s_Iniciar := FALSE;
	                    #s_EstadoImportar := 0;
	                    #s_EstadoBorrar := 0;
	                    #s_RutaCarpeta := #RutaCarpetaRecetas;
	                    #s_EtapaSiguiente := #ETAPA_10_IMPORTAR_ORDEN_HMI;
	                END_IF;
	                
	            END_REGION
	            
	            
	        #ETAPA_10_IMPORTAR_ORDEN_HMI:
	            
	            REGION IMPORTAR_ORDEN_HMI
	                
	                IF #s_OrdenSincHMI THEN
	                    #s_EtapaSiguiente := #ETAPA_20_IMPORTAR_ESPERA_HMI;
	                END_IF;
	                
	                IF #TON_RetardoImportarHmi.Q THEN
	                    #s_OrdenSincHMI := TRUE;
	                END_IF;
	                
	            END_REGION
	            
	            
	        #ETAPA_20_IMPORTAR_ESPERA_HMI:
	            
	            REGION IMPORTAR_ESPERA_HMI
	                
	                IF #TON_EstadoImportar.Q OR #TON_ErrorImportar.Q THEN
	                    #s_EtapaSiguiente := #ETAPA_30_IMPORTAR_COMPROBACION;
	                END_IF;
	                
	            END_REGION
	            
	            
	        #ETAPA_30_IMPORTAR_COMPROBACION:
	            
	            REGION IMPORTAR_COMPROBACION
	                
	                //  Si se ejecuta correctamente, reseteamos marca que indica que hay recetas nuevas que sincronizar
	                //  y guardamos la fecha y hora de la ultima sincronizacion
	                IF #s_EstadoImportar = 4 THEN
	                    
	                    #s_ExisteRecetaNueva :=
	                    #ErrorImportar := FALSE;
	                    #UltimaSincronizacion := #FechaHoraActual;
	                    IF #HabilitarBorrado THEN
	                        #s_EtapaSiguiente := #ETAPA_40_BORRAR_ORDEN_HMI;
	                    ELSE
	                        #s_EtapaSiguiente := #ETAPA_0_REPOSO;
	                    END_IF;
	                ELSE
	                    #ErrorImportar := TRUE;
	                    #s_EtapaSiguiente := #ETAPA_0_REPOSO;
	                END_IF;
	                
	                #s_OrdenSincHMI := FALSE;
	                #s_EstadoImportar := 0;
	                
	                
	            END_REGION
	            
	        #ETAPA_40_BORRAR_ORDEN_HMI:
	            
	            REGION BORRAR_ORDEN_HMI
	                
	                IF #s_OrdenBorrarHMI THEN
	                    #s_EtapaSiguiente := #ETAPA_50_BORRAR_ESPERA_HMI;
	                END_IF;
	                
	                IF #TON_RetardoBorrarHmi.Q THEN
	                    #s_OrdenBorrarHMI := TRUE;
	                END_IF;
	                
	            END_REGION
	            
	            
	        #ETAPA_50_BORRAR_ESPERA_HMI:
	            
	            REGION BORRAR_ESPERA_HMI
	                
	                IF #TON_EstadoBorrar.Q OR #TON_ErrorBorrar.Q THEN
	                    #s_EtapaSiguiente := #ETAPA_60_BORRAR_COMPROBACION;
	                END_IF;
	                
	            END_REGION
	            
	            
	        #ETAPA_60_BORRAR_COMPROBACION:
	            
	            REGION IMPORTAR_COMPROBACION
	                
	                //  Si se ejecuta correctamente, reseteamos marca que indica que hay recetas nuevas que sincronizar
	                //  y guardamos la fecha y hora de la ultima sincronizacion
	                IF #s_EstadoBorrar = 4 THEN
	                    
	                    #s_ExisteRecetaNueva :=
	                    #ErrorBorrar := FALSE;
	                    
	                ELSE
	                    #ErrorBorrar := TRUE;
	                END_IF;
	                
	                #s_EstadoBorrar := 0;
	                #s_OrdenBorrarHMI := FALSE;
	                #s_EtapaSiguiente := #ETAPA_0_REPOSO;
	                
	            END_REGION
	            
	            
	        ELSE
	            
	            #s_EtapaSiguiente := #ETAPA_0_REPOSO;
	            
	    END_CASE;
	    
	    #s_Etapa := #s_EtapaSiguiente;
	    
	END_REGION LOGICA
	
	
END_FUNCTION_BLOCK

