FUNCTION_BLOCK "FB_SensorInput"
{ S7_Optimized_Access := 'TRUE' }
VERSION : 0.1
   VAR_INPUT 
      sInFctName : String[10];   // Sensor Funktion (z.B. Stau)
      sInName : String[10];   // Sensor BMK
      xInSensor : Bool;
      tInDelay : Time := T#150ms;
      tInFlicker : Time := T#20ms;
      tInJamR : Time := T#3000ms;
      tInJamF : Time := T#2000ms;
      tInSenFreeShort : Time := T#4000ms;
      tInSenFreeLong : Time := T#7000ms;
      xInMonitorJam : Bool;
   END_VAR

   VAR_OUTPUT 
      xOutFlickerError : Bool;
      xOutJam : Bool;
      xOutFreeShort : Bool;
      xOutFreeLong : Bool;
      nOutCntFlicker : Int;
   END_VAR

   VAR_IN_OUT 
      stInOutSensor : "UDT_Sensor";
      stInOutHMI : "UDT_HMI_Sensor";
      stInOutControlUnitCabinet : "UDT_MainState";
   END_VAR

   VAR 
      tOnNoSensorChange {InstructionName := 'TON_TIME'; LibVersion := '1.0'} : TON_TIME;
      nCntFlickerPos : Int;
      nCntFlickerNeg : Int;
      xSensorFlag : Bool;
      xSensorDbncdFlag : Bool;
      xSensorDbncd { ExternalAccessible := 'False'; ExternalVisible := 'False'; ExternalWritable := 'False'} : Bool;
      nActualDay : USInt;
      xJam : Bool;
      fbMonitoringJam : "FB_Monitoring";
   END_VAR

   VAR_TEMP 
      tSensor : Bool;
      tDebug : Int;
   END_VAR


BEGIN
	// ------------------------------------------------
	// GLOBAL INFORMATION - do before other FB calls
	// ------------------------------------------------
	
	REGION read inputs
	    #tSensor := (NOT #stInOutHMI.stSensorControl.xControlWithHMI AND #xInSensor) OR
	    (#stInOutHMI.stSensorControl.xControlWithHMI AND #stInOutHMI.stSensorControl.xSensor);
	END_REGION
	
	REGION logic
	    #stInOutSensor.xDirectSensor := #tSensor;
	    #stInOutSensor.xDirectEdgePos := #tSensor AND NOT #xSensorFlag AND NOT "FirstScan";
	    #stInOutSensor.xDirectEdgeNeg := NOT #tSensor AND #xSensorFlag AND NOT "FirstScan";
	    IF #tSensor AND
	        ((#xSensorFlag = #tSensor AND #tOnNoSensorChange.ET >= #tInDelay) OR "FirstScan") THEN
	        #xSensorDbncd := TRUE;
	    ELSIF NOT #tSensor AND
	        ((#xSensorFlag = #tSensor AND #tOnNoSensorChange.ET >= #tInDelay) OR "FirstScan") THEN
	        #xSensorDbncd := FALSE;
	    END_IF;
	    #stInOutSensor.xDbncdEdgePos := #xSensorDbncd AND NOT #xSensorDbncdFlag;
	    #stInOutSensor.xDbncdEdgeNeg := NOT #xSensorDbncd AND #xSensorDbncdFlag;
	END_REGION
	
	REGION detect flickering
	    #xOutFlickerError := FALSE;
	    
	    IF #tSensor AND NOT #xSensorFlag AND    //ging kurzzeitig auf 0
	        #tOnNoSensorChange.ET <= #tInFlicker AND
	        NOT #stInOutHMI.stSensorControl.xControlWithHMI THEN
	        #xOutFlickerError := TRUE;
	        #nCntFlickerNeg += 1;
	    ELSIF
	        NOT #tSensor AND #xSensorFlag AND // geht kurzzeitig auf 1
	        #tOnNoSensorChange.ET <= #tInFlicker AND
	        NOT #stInOutHMI.stSensorControl.xControlWithHMI THEN
	        #xOutFlickerError := TRUE;
	        #nCntFlickerPos += 1;
	    END_IF;
	    
	(*    // Am Ende des Tages die Zähler zurücksetzten
	    IF "DB_MachineGlobal".DTL_TimePLC.DAY <> #nActualDay THEN
	        #nActualDay := "DB_MachineGlobal".DTL_TimePLC.DAY;
	        #nCntFlickerNeg := 0;
	        #nCntFlickerPos := 0;
	    END_IF; *)
	    
	END_REGION
	
	REGION timer
	    #tOnNoSensorChange(IN := (#tSensor = #xSensorFlag),
	                       PT := T#10000S);
	END_REGION
	
	REGION flags
	    #xSensorFlag := #tSensor;
	    #xSensorDbncdFlag := #xSensorDbncd;
	END_REGION
	
	REGION detect jam signal
	    
	    IF #tSensor AND #tOnNoSensorChange.ET > #tInJamR THEN
	        #xJam := TRUE;
	    ELSIF NOT #tSensor AND #tOnNoSensorChange.ET > #tInJamF THEN
	        #xJam := FALSE;
	    END_IF;
	    
	END_REGION
	
	REGION detect if sensor is false for period of time
	    
	    IF NOT #tSensor AND #tOnNoSensorChange.ET > #tInSenFreeShort THEN
	        #xOutFreeShort := TRUE;
	    ELSE
	        #xOutFreeShort := FALSE;
	    END_IF;
	    
	    IF NOT #tSensor AND #tOnNoSensorChange.ET > #tInSenFreeLong THEN
	        #xOutFreeLong := TRUE;
	    ELSE
	        #xOutFreeLong := FALSE;
	    END_IF;
	    
	END_REGION ;
	
	REGION write outputs
	    #xOutJam := #xJam;
	    #stInOutSensor.xDbncdSensor := #xSensorDbncd;
	    #stInOutSensor.sName := #sInName;
	    #stInOutSensor.xJam := #xJam;
	    
	    IF #tOnNoSensorChange.ET >= #tInDelay THEN  //
	        #stInOutSensor.tDirectChangeLast := #tOnNoSensorChange.ET;
	    ELSE
	        #stInOutSensor.tDirectChangeLast := T#0s;
	    END_IF;
	    #nOutCntFlicker := #nCntFlickerNeg + #nCntFlickerPos;
	    
	END_REGION
	
	REGION HMI interface
	    
	    #stInOutHMI.stSensorStatus.sName := #sInName;
	    #stInOutHMI.stSensorStatus.xDirectSensor := #tSensor;
	    #stInOutHMI.stSensorStatus.xDirectEdgePos := #tSensor AND NOT #xSensorFlag AND NOT "FirstScan";
	    #stInOutHMI.stSensorStatus.xDirectEdgeNeg := NOT #tSensor AND #xSensorFlag AND NOT "FirstScan";
	    IF #tOnNoSensorChange.ET >= #tInDelay THEN
	        #stInOutHMI.stSensorStatus.tDirectChangeLast := #tOnNoSensorChange.ET;
	    ELSE
	        #stInOutHMI.stSensorStatus.tDirectChangeLast := T#0s;
	    END_IF;
	    #stInOutHMI.stSensorStatus.xDbncdSensor := #xSensorDbncd;
	    #stInOutHMI.stSensorStatus.xDbncdEdgePos := #xSensorDbncd AND NOT #xSensorDbncdFlag;
	    #stInOutHMI.stSensorStatus.xDbncdEdgeNeg := NOT #xSensorDbncd AND #xSensorDbncdFlag;
	    #stInOutHMI.stSensorStatus.xJam := #xJam;
	    
	    
	END_REGION
	
	REGION monitoring jam
	    #fbMonitoringJam.stSettings.nErrorType := 1;
	    #fbMonitoringJam.stSettings.xErrLedIfMachineIsOff := TRUE;
	    #fbMonitoringJam.stSettings.xSelfQuit := TRUE;
	    #fbMonitoringJam.stSettings.tDelay := T#1s;
	    #fbMonitoringJam(sInFctnName := 'Stauueberwachung',
	                     sInPrefix := #sInFctName,
	                     sInAlarmMessage := 'Sensor meldet Stau',
	                     sInSuffix := #sInName,
	                     wInTextListId_Message := 2,
	                     InOutMachineState := #stInOutControlUnitCabinet,
	                     xInSignal := (NOT #xJam) OR NOT #xInMonitorJam);
	END_REGION
END_FUNCTION_BLOCK

