﻿<?xml version="1.0" encoding="utf-8"?>
<TcPlcObject Version="1.1.0.1">
  <POU Name="localHPUBrake" Id="{bbb7db74-256d-04a7-09d6-ac44bf099fa9}" SpecialFunc="None">
    <Declaration><![CDATA[(*
  This HPU block can be stopped and activated by various winches, which is the reason to activate or stop the HPU
  by a method call

*)
FUNCTION_BLOCK localHPUBrake IMPLEMENTS p7type.IHPUBrake
VAR_INPUT
	ID				: DINT; // has no function other than an identification for the HPU unit and alarm
	Name			: STRING;	// used for alarm text if present	
	Config 			: REFERENCE TO ConfigHPUBrake;
	IO_In			: REFERENCE TO HPUBrakeIO_In;
	IO_Out			: REFERENCE TO HPUBrakeIO_Out;
	OpValues		: REFERENCE TO OpValueHPUBrake;
	EmergencyStop	: BOOL;
END_VAR
VAR
	opTimerCounter 		: ARRAY[0..1] OF p6com.OperationTimeCounter;
	
	state 				: HPUBrakeSM := HPUBrakeSM.START;	// state for the state machine
	Sensor				: p6com.HydPressure250barAA;
	pressureOldValue	: LREAL;
	pumpsw 				: DINT;  							// determines which pump has to be used
	motorproblem		: DINT := 1;
	hours				: ARRAY[0..1] OF UDINT;
	activeFlag 			: BOOL;								// flage for activating HPU
	pressureChangeTimer : TON;
	pressureIsChanging  : BOOL;
	activeTimer 		: TOF;								// timer for have a minimal op time
	errorPressureTimer	: TON;	
	errorPressure		: BOOL;
	startDelay 			: TON;
	oilLevelShutdownTimer : TON;							// Stop HPU if low oil level
	
	{attribute 'hide'} pressureAlarm		: p6com.AlarmDigital(EventEntry := TC_Events.LibPowerEvtClass.HPUBRAKE_PRESSURE_ERROR);
	{attribute 'hide'} oillevelAlarm		: p6com.AlarmDigital(EventEntry := TC_Events.LibPowerEvtClass.HPUBRAKE_OIL_LEVEL_LOW);
	{attribute 'hide'} oiltempAlarm		: p6com.AlarmDigital(EventEntry := TC_Events.LibPowerEvtClass.HPUBRAKE_OIL_TEMP);

END_VAR
]]></Declaration>
    <Implementation>
      <ST><![CDATA[IF areReferencesValid() THEN
	// discard any start signals during startup
	IF startDelay.Q = FALSE THEN
		startDelay(IN := TRUE,PT := T#20S);
		activeFlag := FALSE;
		
		RETURN;
	END_IF
	update();
END_IF]]></ST>
    </Implementation>
    <Method Name="isPressureChanging" Id="{10e95351-4684-0402-3bef-853f57aaa935}">
      <Declaration><![CDATA[METHOD isPressureChanging : BOOL
VAR_INST
	timer : TON;
	lastResult : BOOL := TRUE;;
END_VAR]]></Declaration>
      <Implementation>
        <ST><![CDATA[timer(IN:= NOT timer.Q, PT:=T#1S);

IF timer.Q THEN
	isPressureChanging := ABS(sensor.Value - pressureOldValue) > 1;
	pressureOldValue := sensor.Value;		
	lastResult := isPressureChanging;
ELSE
	isPressureChanging := lastResult;
END_IF




]]></ST>
      </Implementation>
    </Method>
    <Method Name="update" Id="{166f9bff-9b9f-03e5-296a-655bc4117809}">
      <Declaration><![CDATA[METHOD update : BOOL
VAR
	isActive : BOOL;
END_VAR]]></Declaration>
      <Implementation>
        <ST><![CDATA[_calcOpTimes();
pressureIsChanging := isPressureChanging();
isActive := state=HPUBrakeSM.PUMP_ON OR state=HPUBrakeSM.PUMP2 OR state=HPUBrakeSM.PUMP_IDLE;
// According to clarification from Roger 110923, brake HPU should run if e-stop is pressed.
activeTimer(IN := (activeFlag OR EmergencyStop) AND NOT oilLevelShutdownTimer.Q, PT:= Config.OpTimeMin);
Sensor( Io_In := Io_In.PressureSensor);

//
// End start and stop logic
//

errorPressureTimer(IN:=(Sensor.Value < Config.PressureEmergency) AND isActive, PT:=Config.ErrorTime);
IF errorPressureTimer.Q THEN
	errorPressure := TRUE;
ELSE 
	errorPressure := FALSE;
END_IF
	
pressureAlarm(ID:=DINT_TO_UDINT(THIS^.ID), TimeSpan := T#0MS, Value:= errorPressure, IDName:= THIS^.Name );
oillevelAlarm(ID:=DINT_TO_UDINT(THIS^.ID), TimeSpan := T#1S, Value:= NOT IO_In.OilLevelLow, IDName:= THIS^.Name);
oiltempAlarm(ID:=DINT_TO_UDINT(THIS^.ID), TimeSpan := T#5S, Value:= NOT IO_In.TemperatureHigh, IDName:= THIS^.Name);

// stop HPU if no oil in tank for 3 seconds.
oilLevelShutdownTimer(IN:= NOT IO_In.OilLevelLow, PT := T#3S);
IF oilLevelShutdownTimer.Q THEN
	activeTimer(PT:=T#0MS);	//make timer time out	
END_IF


CASE state OF
	HPUBrakeSM.START:
		state := HPUBrakeSM.IDLE;
		
	HPUBrakeSM.IDLE:
		IO_Out.Pump[0] := FALSE;
		IO_Out.Pump[1] := FALSE;
		IF activeTimer.Q AND NOT oilLevelShutdownTimer.Q THEN
			state := HPUBrakeSM.STARTUP;
		END_IF
		
	HPUBrakeSM.STARTUP:
		errorPressure := FALSE;
		IF NOT activeTimer.Q OR oilLevelShutdownTimer.Q THEN
			state := HPUBrakeSM.IDLE;
		ELSIF hours[0] <= hours[1] THEN
			pumpsw := 0;
		ELSE
			pumpsw := 1;
		END_IF
		state := HPUBrakeSM.PUMP_ON;
	
	HPUBrakeSM.PUMP_IDLE:
		IO_Out.Pump[0] := FALSE;
		IO_Out.Pump[1] := FALSE;
		IF NOT activeTimer.Q OR oilLevelShutdownTimer.Q THEN
			state := HPUBrakeSM.IDLE;
		ELSIF Sensor.Value < Config.PressurePumpOn THEN
			state := HPUBrakeSM.PUMP_ON;
		END_IF	
	
	// run selected pump	
	HPUBrakeSM.PUMP_ON:
		IO_Out.Pump[pumpsw] := TRUE;
		IF NOT activeTimer.Q OR oilLevelShutdownTimer.Q THEN
			state := HPUBrakeSM.IDLE;
		ELSIF (Sensor.Value < (Config.PressurePumpOn - 10)) OR (NOT pressureIsChanging) THEN
			state := HPUBrakeSM.PUMP2;
		ELSIF Sensor.Value >= Config.PressureLimit THEN
			state := HPUBrakeSM.PUMP_IDLE;
		END_IF
	
	// run both pumps 
	HPUBrakeSM.PUMP2:
		IO_Out.Pump[0] := TRUE;
		IO_Out.Pump[1] := TRUE;
		IF NOT activeTimer.Q OR oilLevelShutdownTimer.Q THEN
			state := HPUBrakeSM.IDLE;
		ELSIF Sensor.Value >= Config.PressureLimit THEN
			state := HPUBrakeSM.PUMP_IDLE;
		END_IF
END_CASE

// Pumps should run if Estop is on
//IF EmergencyStop THEN
//	IO_Out.Pump[0] := FALSE;
//	IO_Out.Pump[1] := FALSE;
//END_IF

activeFlag := FALSE; // The position of this line is important!
]]></ST>
      </Implementation>
    </Method>
    <Property Name="Pump1Active" Id="{6ffe493d-0a7d-07ed-186c-682c183234f8}">
      <Declaration><![CDATA[{attribute 'TcRpcEnable'}
{attribute 'monitoring':='call'}
PROPERTY Pump1Active : BOOL]]></Declaration>
      <Get Name="Get" Id="{3a67c5c4-b7b0-0558-1537-8d8aa1c44d23}">
        <Declaration><![CDATA[VAR
END_VAR
]]></Declaration>
        <Implementation>
          <ST><![CDATA[Pump1Active := IO_Out.Pump[0];]]></ST>
        </Implementation>
      </Get>
    </Property>
    <Method Name="_calcOpTimes" Id="{7cf89b8a-8b78-09a9-0fcc-eeb1408e50cd}">
      <Declaration><![CDATA[METHOD PRIVATE _calcOpTimes : BOOL
]]></Declaration>
      <Implementation>
        <ST><![CDATA[opTimerCounter[0].update(active :=IO_out.Pump[0], operationTime := OpValues.Optime[0]);
opTimerCounter[1].update(active :=IO_out.Pump[1], operationTime := OpValues.Optime[1]);
hours[0] := TIME_TO_UDINT(OpValues.Optime[0]) / 3600000;
hours[1] := TIME_TO_UDINT(OpValues.Optime[1]) / 3600000;


]]></ST>
      </Implementation>
    </Method>
    <Method Name="setActive" Id="{8937b6d0-6649-099d-28cd-c37250533a63}">
      <Declaration><![CDATA[{attribute 'TcRpcEnable'}
METHOD setActive : BOOL
]]></Declaration>
      <Implementation>
        <ST><![CDATA[THIS^.activeFlag := TRUE;]]></ST>
      </Implementation>
    </Method>
    <Property Name="TemperatureHigh" Id="{89cef589-95cf-0558-07ba-b349d413f41d}">
      <Declaration><![CDATA[{attribute 'TcRpcEnable'}
{attribute 'monitoring':='call'}
PROPERTY TemperatureHigh : BOOL]]></Declaration>
      <Get Name="Get" Id="{3447d9c9-50bc-0771-3dee-0e310baf5d3b}">
        <Declaration><![CDATA[VAR
END_VAR
]]></Declaration>
        <Implementation>
          <ST><![CDATA[TemperatureHigh := oiltempAlarm.Raised;
]]></ST>
        </Implementation>
      </Get>
    </Property>
    <Property Name="Active" Id="{92a42c03-6d2d-0782-13c5-361a09d7780e}">
      <Declaration><![CDATA[{attribute 'monitoring' := 'call'}
{attribute 'TcRpcEnable'}
PROPERTY Active : BOOL]]></Declaration>
      <Get Name="Get" Id="{d272e520-d6d9-024b-183a-a8d8714de16d}">
        <Declaration><![CDATA[VAR
END_VAR
]]></Declaration>
        <Implementation>
          <ST><![CDATA[// added  'PUMP_IDLE' to the equation. HPU is active even if no pumps are running.
Active := state = HPUBrakeSM.PUMP_IDLE  OR state = HPUBrakeSM.PUMP_ON OR state = HPUBrakeSM.PUMP2;]]></ST>
        </Implementation>
      </Get>
    </Property>
    <Method Name="areReferencesValid" Id="{a9886093-2601-08d1-113a-ea7e4f2f3760}">
      <Declaration><![CDATA[{attribute 'TcRpcEnable'}
METHOD areReferencesValid : BOOL

]]></Declaration>
      <Implementation>
        <ST><![CDATA[areReferencesValid := __ISVALIDREF(Config) AND __ISVALIDREF(IO_In) AND __ISVALIDREF(IO_Out) AND __ISVALIDREF(OpValues);
]]></ST>
      </Implementation>
    </Method>
    <Property Name="OilLevelLow" Id="{afed4165-186c-0838-1a48-b495cf8069a9}">
      <Declaration><![CDATA[{attribute 'TcRpcEnable'}
{attribute 'monitoring':='call'}
PROPERTY OilLevelLow : BOOL]]></Declaration>
      <Get Name="Get" Id="{9e1312d3-795a-02f2-04c5-988f831852e4}">
        <Declaration><![CDATA[VAR
END_VAR
]]></Declaration>
        <Implementation>
          <ST><![CDATA[OilLevelLow := oillevelAlarm.Raised;]]></ST>
        </Implementation>
      </Get>
    </Property>
    <Property Name="Pump2Active" Id="{b05081f6-8f67-060e-3bcd-bdb357ba3d68}">
      <Declaration><![CDATA[{attribute 'TcRpcEnable'}
{attribute 'monitoring':='call'}
PROPERTY Pump2Active : BOOL]]></Declaration>
      <Get Name="Get" Id="{f5de066e-7e3b-00d7-1fa9-0e68d1b47c31}">
        <Declaration><![CDATA[VAR
END_VAR
]]></Declaration>
        <Implementation>
          <ST><![CDATA[Pump2Active := IO_Out.Pump[1];]]></ST>
        </Implementation>
      </Get>
    </Property>
    <Property Name="PressureOK" Id="{d68f89bc-ccfb-04ac-0ab4-6448a876af3b}">
      <Declaration><![CDATA[{attribute 'monitoring' := 'call'}
{attribute 'TcRpcEnable'}
PROPERTY PressureOK : BOOL]]></Declaration>
      <Get Name="Get" Id="{5e8d280a-1840-0e2d-3178-8664f4aff1c4}">
        <Declaration><![CDATA[VAR
END_VAR
]]></Declaration>
        <Implementation>
          <ST><![CDATA[// report oil pressure as not OK if pump has stopped due to low oil level
PressureOK := Sensor.Value > Config.PressureEmergency AND NOT oilLevelShutdownTimer.Q;
]]></ST>
        </Implementation>
      </Get>
    </Property>
    <Property Name="Error" Id="{d9faef0d-bfc5-022a-0da4-3c92926e57bc}">
      <Declaration><![CDATA[{attribute 'monitoring' := 'call'}
{attribute 'TcRpcEnable'}
PROPERTY Error : BOOL]]></Declaration>
      <Get Name="Get" Id="{0988aa10-a7c7-03d4-2750-e2c617ec15dd}">
        <Declaration><![CDATA[VAR
END_VAR
]]></Declaration>
        <Implementation>
          <ST><![CDATA[Error := oillevelAlarm.Raised OR oiltempAlarm.Raised OR pressureAlarm.Raised;
]]></ST>
        </Implementation>
      </Get>
    </Property>
    <Property Name="Pressure" Id="{ecdb5e2b-82ed-04da-37d2-d0a815400403}">
      <Declaration><![CDATA[{attribute 'TcRpcEnable'}
{attribute 'monitoring':='call'}
PROPERTY Pressure : LREAL]]></Declaration>
      <Get Name="Get" Id="{04119fad-d442-02ba-1abe-08a8cce78b6a}">
        <Declaration><![CDATA[]]></Declaration>
        <Implementation>
          <ST><![CDATA[Pressure := sensor.Value;]]></ST>
        </Implementation>
      </Get>
    </Property>
  </POU>
</TcPlcObject>