﻿<?xml version="1.0" encoding="utf-8"?>
<TcPlcObject Version="1.1.0.1">
  <POU Name="LocalBaseUserWinch" Id="{d74afaf2-48c1-41cf-a315-d8cc807a0af2}" SpecialFunc="None">
    <Declaration><![CDATA[(*
The standard winch used for aux-winches etc
*)
FUNCTION_BLOCK LocalBaseUserWinch IMPLEMENTS p7type.IBaseUserWinch
VAR_INPUT
	WinchID									: DINT;
	configUserWinch							: REFERENCE TO ConfigTorqueWinch_local;	
	IO_In									: REFERENCE TO WinchIO_In;
	IO_Out									: REFERENCE TO WinchIO_Out;
	Winch									: IWinch;
	GearCooling								: IGearCoolingWinch;
	MotorCooling							: IMotorCoolingWinch;
	EmergencyStop							: p6com.IEmergencyStop;
	Enable 									: BOOL := TRUE;
	DriveConfig								: REFERENCE TO p7elec.ConfigElectricDrive; // Only used to get gear ratio 
END_VAR
VAR
	{attribute 'hide'} _controlUnitInControl 	: IBaseControlUnit;
	{attribute 'hide'} _winch 					: IWinch;
	{attribute 'hide'} _emergencyStop 			: p6com.IEmergencyStop;
	
	{attribute 'hide'} _State : p7type.UserWinchStates;
	{attribute 'hide'} _winchManualMode : p7type.WinchManualModes;	
	{attribute 'hide'} _winchMode		: p7type.WinchModes;

	{attribute 'hide'} _potmeterReference : LREAL; 		// Reference value from potmeter on user control
	{attribute 'hide'} _joystickInCentre : BOOL;
	{attribute 'hide'} _velocityReference : LREAL;		// drum RPM, NEGATIVE is haul in
	{attribute 'hide'} _torqueReference : LREAL;		// Normalized torque, POSITIVE is haul in
	{attribute 'hide'} _winchCMD : WinchCMD;
	{attribute 'hide'} _activateWinch : BOOL;				// signal from controlUnit. Puls that is only TRUE during one scan
		
	{attribute 'hide'} _velocityReferenceAuto : LREAL;
	{attribute 'hide'} _torqueReferenceAuto : LREAL;
	
	{attribute 'hide'} _newControlUnitAssigned : BOOL;
		
	{attribute 'hide'} _timeoutActive : TON;
	{attribute 'hide'} _reducedSpeedAndTension : BOOL;		// Can be used by user winches to force speed and torque reduction
	{attribute 'hide'} _preventTimeout : BOOL; 			// Can be used by user winches to prevent that winch times out. Ex. PS winches while clutched out.
	{attribute 'hide'} _cooperatingWinchRotating : BOOL;
	{attribute 'hide'} _activeAndNotRotating : BOOL;	
	{attribute 'hide'} _noVelocityReference : BOOL;
	
	{attribute 'hide'} _requestAutoMode : BOOL;
	
	_coolingAvailable 	: BOOL;
	_coolingOP 			: BOOL;		
	_coolingNoOPTimer	: TON;
	
	{attribute 'hide'} _opstate 					: p6com.P6OpState;
	
	{attribute 'hide'} _emergencyStop_Falling : F_TRIG;	// Used to recover from emergency stop
	{attribute 'hide'} man_timer : TON;
	{attribute 'hide'} _inhibitManualRotation : BOOL;		// prevent winch from rotation, Set torque to Max
	{attribute 'hide'}_blockStop : BOOL;				// inhibit haul In (class property)
	{attribute 'hide'}_reduceConstantTorque : BOOL;		// reduce tension if in C.T. mode (class property)
	constTorqueDeactivateTimer		: TON;				// wait for drive speed to ramp down after CT
	ff_torque_Nm					: LREAL;			// calculated feed forward torque used in PID
	CT_rampdownTime 				: TIME ;			// how long to wait for VFD speed ramp Down.
	CT_rampdownInit					: BOOL := TRUE;		// run once when entering CT cooldown
	CT_rampUpInit					: BOOL := TRUE;		// run once when entering CT mode to set ramp time
	CT_initSpeed					: LREAL ;			// used to store current drum RPM  when entering CT mode
	CT_rampedLimitpay				: LREAL ;			// will ramp up/down from current speed to CT.TorqueModePIDspeedLimitPay
	CT_rampedLimitHaul				: LREAL ;			// will ramp up/down from current speed to CT.TorqueModePIDspeedLimitHaul
	CT_rampChangePerScan			: LREAL ;			// RPM change per scan
	CT_internalTensionSetpoint		: LREAL ;			// Not in use
	driveGearRatio					: LREAL := 100;		// Default value, pick from Drive config if available.
	
	

	
END_VAR
]]></Declaration>
    <Implementation>
      <ST><![CDATA[_winch := Winch;
_emergencyStop := EmergencyStop;
// tell the winch which name to use
_winch.IDname := configUserWinch.name;

IF __ISVALIDREF(DriveConfig) THEN
	driveGearRatio := DriveConfig.gearRatio;
END_IF

// if we're case insensitive, what's the purpose with this?
gearCooling := GearCooling;
motorCooling := MotorCooling;

_coolingOP := (_coolingAvailable AND configUserWinch.optionMotorCoolingIsMandatory) OR 
				(NOT configUserWinch.optionMotorCoolingIsMandatory);
				
_coolingNoOPTimer(IN:=NOT _coolingOP, PT:=T#10S);
				
IF (_winch = 0 OR _emergencyStop = 0) THEN
	RETURN; // just quit if not initialized. Needs this to operate correct!
END_IF

// When emergency stop present in system force state machine to emergency stop! 
IF _emergencyStop.Activated THEN
	_State := p7type.UserWinchStates.EMERGENCYSTOP;
END_IF
_emergencyStop_Falling(CLK := _emergencyStop.Activated);

// Use 5 if not initialized. Prevents division by 0.
IF configUserWinch.turtleModeSpeedDivident = 0 THEN
	configUserWinch.turtleModeSpeedDivident := 5;
END_IF;

// Check manual winch mode requested from control unitInControl
THIS^._determineWinchManualMode(); // note: may be ovverridden in other winch classes
THIS^._handleGearCooling();
THIS^._controlParkingBrakes();
THIS^._handleMotorCooling();

IF _controlUnitInControl <> 0 THEN
	_cooperatingWinchRotating := _controlUnitInControl.CooperatingWinchIsRotating;
	_potmeterReference := _controlUnitInControl.PotmeterReference;
	_joystickInCentre := _controlUnitInControl.JoystickInCentre;
	_activateWinch := _controlUnitInControl.ActivateWinch;
ELSE
	_cooperatingWinchRotating := 0;
	_potmeterReference := 1;
	_joystickInCentre := FALSE;
	_activateWinch := FALSE;
END_IF

man_timer(IN := _State = p7type.UserWinchStates.MANUAL ,PT:=T#50MS);



// Handle timeout of winch
_activeAndNotRotating := ((_State = p7type.UserWinchStates.MANUAL_ACTIVE OR _State = p7type.UserWinchStates.MANUAL_ACTIVE_REDUCED) AND NOT _winch.IsRotating);
_noVelocityReference := (_velocityReference < 0.01 AND _velocityReference > -0.01);
_timeoutActive(IN := (NOT _activateWinch AND _activeAndNotRotating AND 
						_noVelocityReference AND NOT _preventTimeOut AND 
					NOT _cooperatingWinchRotating AND (_State<>p7type.UserWinchStates.AUTO)), PT := configUserWinch.activeTimeOut);
	
CASE _State OF 
	p7type.UserWinchStates.INACTIVE:
		_opstate := p6com.P6OpState.STOPPED;
		_winchMode := p7type.WinchModes.IDLE;
		
		_newControlUnitAssigned := FALSE;
		
		_winchCMD := WinchCMD.STOP;
		_velocityReference := 0;
		_torqueReference := 1;
		_winch.setOperation(_winchCMD, _velocityReference, _torqueReference, 0, 0, 0 , 0);
		
		IF _controlUnitInControl <> 0 THEN
			_controlUnitInControl.StopWinch := FALSE;

			IF _activateWinch AND _winch.isReadyToActivate THEN 
				CASE _winchManualMode OF
					WinchManualModes.NORMAL,
					WinchManualModes.MANUAL_TORQUE:
						_State := p7type.UserWinchStates.MANUAL;
						_opstate := p6com.P6OpState.PREPARE;
					WinchManualModes.CONSTANT_TORQUE:
						_State := p7type.UserWinchStates.CONST_TORQUE;					
						_opstate := p6com.P6OpState.PREPARE;
				END_CASE
			END_IF
		END_IF
	
	p7type.UserWinchStates.MANUAL:
		_winchMode := p7type.WinchModes.MANUAL;
		_opstate := p6com.P6OpState.PREPARE;
		_velocityReference := 0;
		_torqueReference := 1;
		_winchCMD := WinchCMD.MANUAL;
		_winch.setOperation(_winchCMD, _velocityReference, _torqueReference, 0, 0, 0 , 0);
		IF man_timer.Q THEN
			_State := p7type.UserWinchStates.MANUAL_PREPARE;			
		END_IF

	p7type.UserWinchStates.MANUAL_PREPARE:
		_winchMode := p7type.WinchModes.MANUAL;
		_opstate := p6com.P6OpState.PREPARE;

		IF winchDriverStopped() THEN
			_State := p7type.UserWinchStates.INACTIVE;			
		ELSE
			_State := p7type.UserWinchStates.MANUAL_PREOP;
		END_IF
		
	p7type.UserWinchStates.MANUAL_PREOP:
		_winchMode := p7type.WinchModes.MANUAL;
		_opstate := p6com.P6OpState.PREPARE;
		_winchCMD := WinchCMD.MANUAL;
		_velocityReference := 0;
		
		_torqueReference := 1;
	
		_winch.setOperation(_winchCMD, _velocityReference, _torqueReference, 0, 0, 0 , 0);

		IF winchDriverStopped() THEN
			_State := p7type.UserWinchStates.INACTIVE;				// Something wrong with inverters, user needs to reset inverters from HMI.
		ELSIF _winch.OpState = p6com.P6OpState.RUN THEN
			_State := p7type.UserWinchStates.MANUAL_ACTIVE;
		END_IF
		
	p7type.UserWinchStates.MANUAL_ACTIVE:
		_winchMode := p7type.WinchModes.MANUAL; 	
		_opstate := p6com.P6OpState.RUN;
		IF _coolingNoOPTimer.Q THEN
			_State := p7type.UserWinchStates.InActive;
			RETURN;
		ELSIF _controlUnitInControl = 0 THEN
			_State := p7type.UserWinchStates.InActive;
			RETURN;
		END_IF
		
		IF _controlUnitInControl.TurtleMode THEN
			_velocityReference := _controlUnitInControl.VelocityReference/configUserWinch.turtleModeSpeedDivident;		// When in turtle mode speed is reduced by a factor of 5
		ELSE
			_velocityReference := _controlUnitInControl.VelocityReference;
		END_IF
		IF (_blockStop OR IO_in.blockStopInput ) AND _velocityReference < 0 THEN		// block Stop only in haul in.
			_velocityReference := 0;
		END_IF
		
														// normal operation
		_winchCMD := WinchCMD.MANUAL;
		CASE _winchManualMode OF
			WinchManualModes.NORMAL:
				_velocityReference := _velocityReference;						
				_torqueReference := 1.0;										
			WinchManualModes.MANUAL_TORQUE:
				_winchCMD := WinchCMD.MANUAL;
				_velocityReference := _velocityReference;					
				_torqueReference := _potmeterReference;									
		END_CASE
		
		IF _requestAutoMode THEN
			_State := p7type.UserWinchStates.AUTO;
		END_IF
		IF _inhibitManualRotation THEN		// don't let winch rotate (external command from SDR controller)
			_velocityReference := 0;
			_torqueReference := 1;
		END_IF
		_winch.setOperation(CMD := _winchCMD, 
								Setpoint := _velocityReference, 
								parameter1 := _torqueReference, 
								parameter2 := 0, 
								parameter3 := 0, 
								parameter4 := 0, 
								AHC := 0); 

		IF _timeoutActive.Q OR  (NOT Enable) OR _newControlUnitAssigned  OR winchDriverStopped() OR _controlUnitInControl.StopWinch THEN
			_State := p7type.UserWinchStates.INACTIVE;
		ELSIF _winchManualMode = WinchManualModes.CONSTANT_TORQUE THEN
			_State := p7type.UserWinchStates.CONST_TORQUE;					
		ELSIF _requestAutoMode THEN
			_State := p7type.UserWinchStates.AUTO;
		ELSIF THIS^._reducedSpeedAndTension THEN
			_State := p7type.UserWinchStates.MANUAL_ACTIVE_REDUCED;
		END_IF
		
	// This mode forces winch to move slow and with reduced tension. Ex. when clutch in/out.
	p7type.UserWinchStates.MANUAL_ACTIVE_REDUCED:
		_winchMode := p7type.WinchModes.MANUAL;
		_opstate := p6com.P6OpState.RUN;
		IF _coolingNoOPTimer.Q THEN
			_State := p7type.UserWinchStates.InActive;
			RETURN;
		ELSIF _controlUnitInControl = 0 THEN
			_State := p7type.UserWinchStates.InActive;
			RETURN;
		END_IF
		
		_velocityReference := _controlUnitInControl.VelocityReference/configUserWinch.turtleModeSpeedDivident;		// When in turtle mode speed is reduced by a factor of 5
	
		_winchCMD := WinchCMD.MANUAL;
		_velocityReference := _velocityReference;
		_torqueReference := configUserWinch.reducedTensionLevel;
		IF _requestAutoMode THEN
			_State := p7type.UserWinchStates.AUTO;
		END_IF
		
		_winch.setOperation(CMD := _winchCMD, 
								Setpoint := _velocityReference, 
								parameter1 := _torqueReference, 
								parameter2 := 0, 
								parameter3 := 0, 
								parameter4 := 0, 
								AHC := 0); 

		IF _timeoutActive.Q OR (NOT Enable) OR _newControlUnitAssigned  OR winchDriverStopped() THEN 
			_State := p7type.UserWinchStates.INACTIVE;
		ELSIF _requestAutoMode THEN
			_State := p7type.UserWinchStates.AUTO;
		// If criteria for reducing speed and tension is lost go back to normal mode. Only allowed when winch is not moving. 
		// This makes sure that winch doesnt start to move fast suddenly.
		ELSIF NOT THIS^._reducedSpeedAndTension AND NOT _winch.IsRotating THEN
			_State := p7type.UserWinchStates.MANUAL_ACTIVE;
		END_IF		
		
	
	p7type.UserWinchStates.CONST_TORQUE:
		_winchMode := p7type.WinchModes.TORQUE;
		_opstate := p6com.P6OpState.PREPARE;
		CT_initSpeed := _velocityReference; 	// store current speed.
		_velocityReference := 0;				// maybe skip this?
		_torqueReference := 1;
		_winchCMD := WinchCMD.TORQUE;
		_winch.setOperation(_winchCMD, _torqueReference, _velocityReference, 0, 0, 0 , 0);
		_State := p7type.UserWinchStates.CONST_TORQUE_PREPARE;

	p7type.UserWinchStates.CONST_TORQUE_PREPARE:
		_winchMode := p7type.WinchModes.TORQUE;
		_opstate := p6com.P6OpState.PREPARE;

		IF winchDriverStopped() THEN
			_State := p7type.UserWinchStates.INACTIVE;			
		ELSE
			_State := p7type.UserWinchStates.CONST_TORQUE_PREOP;
		END_IF
		
	p7type.UserWinchStates.CONST_TORQUE_PREOP:
		_winchMode := p7type.WinchModes.TORQUE;
		_opstate := p6com.P6OpState.PREPARE;
		_winchCMD := WinchCMD.TORQUE;
		_velocityReference := 0;				// skip this too?
		_torqueReference := 1;
		_winch.setOperation(_winchCMD, _torqueReference, _velocityReference, 0, 0, 0 , 0);
		
		

		IF winchDriverStopped() THEN
			_State := p7type.UserWinchStates.INACTIVE;				// Something wrong with inverters, user needs to reset inverters from HMI.
		ELSIF _winch.OpState = p6com.P6OpState.RUN THEN
			_State := p7type.UserWinchStates.CONST_TORQUE_ACTIVE;
			CT_rampUpInit := TRUE;	//
		END_IF	
		
	p7type.UserWinchStates.CONST_TORQUE_ACTIVE:
		CT_rampdownInit := TRUE;					// prepare for rampdown init
		_winchMode := p7type.WinchModes.TORQUE;
		_opstate := p6com.P6OpState.RUN;
		IF _coolingNoOPTimer.Q THEN
			_State := p7type.UserWinchStates.InActive;
			RETURN;
		ELSIF _controlUnitInControl = 0 THEN
			_State := p7type.UserWinchStates.InActive;
			RETURN;
		END_IF
		
		// If user has enabled use of safety distance 
		// the winch will get 0 RPM in speed reference if within safety range.
		// This is used by net sounder winch.
		IF (configUserWinch.optionSafetyDistanceEnabled AND (_winch.Length < configUserWinch.safetyDistance)) OR
			(_blockStop OR IO_in.blockStopInput ) THEN		
			_velocityReference := 0;									// Velocity
		ELSE
			_velocityReference := configUserWinch.speedConstantTorque;	// Velocity						
		END_IF

		IF configUserWinch.optionConstTorqueFromConfig THEN 
			// use reduced level if docking head is half compressed
			_torqueReference := SEL((_reduceConstantTorque OR IO_In.reduceConstantTorqueInput),configUserWinch.constTorqueRel , configUserWinch.constTorqueRelReduced);
		ELSE	// use potmeter signal
			_torqueReference := _potmeterReference;
		END_IF
		
		// ***************   SuperCT start **************************** 
		IF configUserWinch.CT_config.PIDactive AND CT.isSensorsOK THEN	
			IF CT_rampUpInit THEN	
				CT_rampedLimitpay 	:= MIN(ABS(CT_initSpeed),2);
				CT_rampedLimitHaul := MIN(ABS(CT_initSpeed),2);
				CT_rampUpInit := FALSE;
			END_IF
			
			// ******ramp up/down ********
			CT_rampChangePerScan := configUserWinch.CT_config.SpeedRampRate / 100.0 ; // 100 scans per second
			
			IF CT_rampedLimitpay < configUserWinch.CT_config.TorqueModePIDspeedLimitPay THEN
				CT_rampedLimitpay := CT_rampedLimitpay + CT_rampChangePerScan;
				IF CT_rampedLimitpay > configUserWinch.CT_config.TorqueModePIDspeedLimitPay THEN CT_rampedLimitpay := configUserWinch.CT_config.TorqueModePIDspeedLimitPay; END_IF;
			ELSIF CT_rampedLimitpay > configUserWinch.CT_config.TorqueModePIDspeedLimitPay THEN
				CT_rampedLimitpay := CT_rampedLimitpay - CT_rampChangePerScan;
				IF CT_rampedLimitpay < configUserWinch.CT_config.TorqueModePIDspeedLimitPay THEN CT_rampedLimitpay := configUserWinch.CT_config.TorqueModePIDspeedLimitPay; END_IF;
			END_IF;
			
			IF CT_rampedLimitHaul < configUserWinch.CT_config.TorqueModePIDspeedLimitHaul THEN
				CT_rampedLimitHaul := CT_rampedLimitHaul + CT_rampChangePerScan;
				IF CT_rampedLimitHaul > configUserWinch.CT_config.TorqueModePIDspeedLimitHaul THEN CT_rampedLimitHaul := configUserWinch.CT_config.TorqueModePIDspeedLimitHaul; END_IF;
			ELSIF CT_rampedLimitHaul > configUserWinch.CT_config.TorqueModePIDspeedLimitHaul THEN
				CT_rampedLimitHaul := CT_rampedLimitHaul - CT_rampChangePerScan;
				IF CT_rampedLimitHaul < configUserWinch.CT_config.TorqueModePIDspeedLimitHaul THEN CT_rampedLimitHaul := configUserWinch.CT_config.TorqueModePIDspeedLimitHaul; END_IF;
			END_IF;
			
			// UDP logging:
			CT.processData.speedRampPay  := CT_rampedLimitpay;
			CT.processData.speedRampHaul := CT_rampedLimitHaul;
			
			IF  configUserWinch.CT_config.selectedPIDtype = 3  THEN 		// automatic tension step
				configUserWinch.CT_config.TargetTension_kg := SEL(CT.s_20_toggle, configUserWinch.CT_config.simTensionLowValue,configUserWinch.CT_config.simTensionHighValue); 
			END_IF	
			
			//  Torque PID (default mode)
			IF  configUserWinch.CT_config.selectedPIDtype = 1 OR configUserWinch.CT_config.selectedPIDtype = 3  THEN	
				
				IF CT.isIndoors THEN
					CT.torquePID.SetCmdLimits(  minimum := LIMIT (configUserWinch.CT_config.indoorMinTorqueLimit_Nm , configUserWinch.CT_config.kN_Speed_limit_factor *( CT.processData.TractionWinchActualRPM - CT_rampedLimitpay), configUserWinch.CT_config.indoorMaxTorqueLimit_Nm), 
												maximum := LIMIT (configUserWinch.CT_config.indoorMinTorqueLimit_Nm , configUserWinch.CT_config.kN_Speed_limit_factor *( CT.processData.TractionWinchActualRPM + CT_rampedLimitHaul), configUserWinch.CT_config.indoorMaxTorqueLimit_Nm));
				ELSE // outside
					CT.torquePID.SetCmdLimits(  minimum := LIMIT (configUserWinch.CT_config.outdoorMinTorqueLimit_Nm , configUserWinch.CT_config.kN_Speed_limit_factor *( CT.processData.TractionWinchActualRPM - CT_rampedLimitpay), configUserWinch.CT_config.outdoorMaxTorqueLimit_Nm), 
												maximum := LIMIT (configUserWinch.CT_config.outdoorMinTorqueLimit_Nm , configUserWinch.CT_config.kN_Speed_limit_factor *( CT.processData.TractionWinchActualRPM + CT_rampedLimitHaul), configUserWinch.CT_config.outdoorMaxTorqueLimit_Nm));
				END_IF
				
				CT.torquePID.SetCoeffs(	loopTime := 0.01, 
						Kp := configUserWinch.CT_PIDconfig.Kp, 
						Ki := configUserWinch.CT_PIDconfig.Ki, 
						Kd :=  configUserWinch.CT_PIDconfig.Kd, 
						Tf := configUserWinch.CT_PIDconfig.Tf);
				
				// To take away some of the proportional error, we're subtracting the minimum backtension setting from the target tension. Backtension will usually be higher than this, but the regulator takes care of this.
				ff_torque_Nm := (configUserWinch.CT_config.TargetTension_kg - gvlStorageDrum01.SDR_controller.config.minimumBackTension) * 9.81 * (gvlTractionWinch01.eWinch.Config.CoreDiameter/2) / (gvlTractionWinch01.Drive.getGearRatio()* 2 );
				CT.torquePID.SetFeedForward(FF := ff_torque_Nm );	// Nm
				
				CT.torqueCommand := CT.torquePID.CommandSignal(referenceInput := configUserWinch.CT_config.TargetTension_kg , measurement := CT.processData.LoadcellTension);
				_velocityReference := configUserWinch.CT_config.VFD_drum_RPM_limit;
				// positive torque hauls in. (we invert this later in the process)		
				_torqueReference := (CT.torqueCommand / configUserWinch.CT_config.motorNominalTorque_Nm )   ;	// divide by motor nominal torque Nm to get normalized value 
			END_IF
			
			//  Direct torque step simulation
			IF configUserWinch.CT_config.selectedPIDtype = 2 THEN	
				_velocityReference := -1.0; // SLOW TESTING
				_torqueReference := SEL(CT.s_10_toggle, configUserWinch.CT_config.simTorqueLowValue,configUserWinch.CT_config.simTorqueHighValue);
			END_IF
		END_IF
		
		// ***************   SuperCT end **************************** 
		
		_winch.setOperation( CMD := _winchCMD, 
								Setpoint := _torqueReference, 
								parameter1 := _velocityReference, 
								parameter2 := 0, 
								parameter3 := 0, 
								parameter4 := 0, 
								AHC := 0); 	

		IF _timeoutActive.Q OR (NOT Enable) OR _newControlUnitAssigned  OR winchDriverStopped() OR _controlUnitInControl.StopWinch THEN 
			_State := p7type.UserWinchStates.INACTIVE;
		ELSIF (_winchManualMode = WinchManualModes.NORMAL) OR (_winchManualMode = WinchManualModes.MANUAL_TORQUE) THEN
			_State := p7type.UserWinchStates.CONST_TORQUE_DEACTIVATE ; // Cool down speed before returning to normal operation
		ELSIF _requestAutoMode THEN
			_State := p7type.UserWinchStates.AUTO;
		END_IF
		
		

	p7type.UserWinchStates.CONST_TORQUE_DEACTIVATE:
		
		IF configUserWinch.CT_config.PIDactive AND CT.isSensorsOK THEN
			IF CT_rampdownInit THEN 
				CT_rampdownInit := FALSE;
				// (Motor RPM  * 8 / 20000) gives time in seconds, multiply by 1000 to get ms
				CT_rampdownTime := LREAL_TO_TIME(( ABS(configUserWinch.CT_config.VFD_drum_RPM_limit) * driveGearRatio * (* VFD ramp time *) 8  * 1000 )/ (* VFD Speed scaling *) 20000 ) ;
			END_IF 
		ELSE
			CT_rampdownTime := T#1S;
		END_IF
		
		constTorqueDeactivateTimer(IN := TRUE, PT := CT_rampdownTime);
		_winchMode := p7type.WinchModes.TORQUE;
		_opstate := p6com.P6OpState.RUN;
		_winchCMD := WinchCMD.TORQUE;
		IF _controlUnitInControl = 0 THEN
			_State := p7type.UserWinchStates.InActive;
			RETURN;
		END_IF
		
		
		IF configUserWinch.CT_config.PIDactive AND CT.isSensorsOK THEN   						// We came from CT PID....		
			_torqueReference := ff_torque_Nm / configUserWinch.CT_config.motorNominalTorque_Nm ;		// CHECK!
		ELSIF configUserWinch.optionConstTorqueFromConfig THEN 
			// use reduced level if docking head is half compressed
			_torqueReference := SEL((_reduceConstantTorque OR IO_In.reduceConstantTorqueInput),configUserWinch.constTorqueRel , configUserWinch.constTorqueRelReduced);
		ELSE
			_torqueReference := _potmeterReference;
		END_IF
		
		_velocityReference := 0;
		_winch.setOperation( CMD := _winchCMD, 
							Setpoint := _torqueReference, 
							parameter1 := _velocityReference, 
							parameter2 := 0, 
							parameter3 := 0, 
							parameter4 := 0, 
							AHC := 0); 	
		IF constTorqueDeactivateTimer.Q THEN		// turns on after the specified time				
			constTorqueDeactivateTimer(IN := FALSE);
			_State := p7type.UserWinchStates.MANUAL_PREPARE;
		END_IF
	
		
		
	// Auto states: velocity and torque references received from TrawlControl via TrawlWinch.SetAutoOperation(...);
	
	p7type.UserWinchStates.AUTO:					// if this is the state we always go into, should it go directly to AUTO_ACTIVE
		_winchMode := p7type.WinchModes.AUTO;
		_opstate := p6com.P6OpState.PREPARE;
		_velocityReference := 0; //   was _velocityReferenceAuto;
		_torqueReference := _torqueReferenceAuto;
		_State := p7type.UserWinchStates.AUTO_PREPARE;  // was AUTO_ACTIVE
	
	p7type.UserWinchStates.AUTO_PREPARE:
		_winchMode := p7type.WinchModes.AUTO;
		_opstate := p6com.P6OpState.PREPARE;
		IF winchDriverStopped() THEN
			_State := p7type.UserWinchStates.MANUAL_ACTIVE;			
		ELSE
			_State := p7type.UserWinchStates.AUTO_PREOP;
		END_IF		

	p7type.UserWinchStates.AUTO_PREOP:		
		_winchMode := p7type.WinchModes.AUTO;
		_opstate := p6com.P6OpState.PREPARE;
		_velocityReference := 0 ; //_velocityReferenceAuto;
		_torqueReference := _torqueReferenceAuto;
		_winchCMD := WinchCMD.SLAVE;
		_winch.setOperation(_winchCMD, _velocityReference, _torqueReference, 0, 0, 0 , 0);
		
		IF winchDriverStopped() THEN
			_State := p7type.UserWinchStates.INACTIVE;				// Something wrong with inverters, user needs to reset inverters from HMI.
		ELSIF _winch.OpState = p6com.P6OpState.RUN THEN
			_State := p7type.UserWinchStates.AUTO_ACTIVE;
		END_IF
		
	p7type.UserWinchStates.AUTO_ACTIVE:

		_winchMode := p7type.WinchModes.AUTO;
		_opstate := p6com.P6OpState.RUN;
		_velocityReference := _velocityReferenceAuto;
		_torqueReference := _torqueReferenceAuto;
		_winchCMD := WinchCMD.SLAVE;
		_winchManualMode := WinchManualModes.NORMAL;	// make sure we're not in any costant or manual torque moed.
		_winch.setOperation(_winchCMD, _velocityReference, _torqueReference, 0, 0, 0 , 0);

		IF _coolingNoOPTimer.Q THEN
			_State := p7type.UserWinchStates.InActive;
			RETURN;
		ELSIF winch.State <> p7type.P6State.OP THEN
			_State := p7type.UserWinchStates.INACTIVE;
		ELSIF NOT _requestAutoMode THEN
			_State := p7type.UserWinchStates.MANUAL_ACTIVE;
			_winchCMD := WinchCMD.MANUAL;
			_winch.setOperation(_winchCMD, _velocityReference, _torqueReference, 0, 0, 0 , 0);
		END_IF
		
	p7type.UserWinchStates.EMERGENCYSTOP:	
		_winchMode := p7type.WinchModes.ESTOP;
		_opstate := p6com.P6OpState.NOTAVAILABLE;
		_winchCMD := WinchCMD.FASTSTOP;
		_velocityReference := 0;
		_torqueReference := 1;
		_winch.setOperation(_winchCMD, _velocityReference, _torqueReference, 0, 0, 0 , 0);

		IF _emergencyStop_Falling.Q THEN
			_winchCMD := WinchCMD.FASTSTOP_OFF;
			_velocityReference := 0;
			_torqueReference := 1;
			_winch.setOperation(_winchCMD, _velocityReference, _torqueReference, 0, 0, 0 , 0);			
			// Exit emergency stop when clear. Enter inactive state to make sure winch needs to be activated to move again. 
			_State := p7type.UserWinchStates.INACTIVE;
		END_IF
END_CASE
]]></ST>
    </Implementation>
    <Property Name="ManMode" Id="{0163ebd4-b9df-4a78-9eae-166d94c97c43}">
      <Declaration><![CDATA[// The current mode the winch is running in
{attribute 'TcRpcEnable'}
{attribute 'monitoring':='call'}
PROPERTY ManMode : WinchManualModes]]></Declaration>
      <Get Name="Get" Id="{59b39c83-4730-4086-a332-318ef3c3a26d}">
        <Declaration><![CDATA[VAR
END_VAR
]]></Declaration>
        <Implementation>
          <ST><![CDATA[ManMode := _winchManualMode;]]></ST>
        </Implementation>
      </Get>
    </Property>
    <Property Name="IsRotating" Id="{0943fc97-f0a5-4bde-83ab-fce05b3236fe}">
      <Declaration><![CDATA[(* When the winch is rotating faster than config.winchIsRotatingValue this property is true *)
{attribute 'monitoring' := 'call'}
{attribute 'TcRpcEnable'}
PROPERTY IsRotating : BOOL]]></Declaration>
      <Get Name="Get" Id="{6881ff4c-6424-4701-ade4-0813a94961a3}">
        <Declaration><![CDATA[VAR
END_VAR
]]></Declaration>
        <Implementation>
          <ST><![CDATA[IsRotating := _winch.IsRotating;]]></ST>
        </Implementation>
      </Get>
    </Property>
    <Property Name="TorqueMax" Id="{0cbfc992-adad-4101-8914-c4a0024e13d9}">
      <Declaration><![CDATA[// Maximum Wire torque in Nm for this winch
{attribute 'monitoring':='call'}
{attribute 'TcRpcEnable'}
PROPERTY TorqueMax : LREAL]]></Declaration>
      <Get Name="Get" Id="{ac889865-9459-4e71-a2d3-9d162737381d}">
        <Declaration><![CDATA[VAR
END_VAR
]]></Declaration>
        <Implementation>
          <ST><![CDATA[TorqueMax := _winch.TorqueMax;]]></ST>
        </Implementation>
      </Get>
    </Property>
    <Method Name="_preventWinchTimeOut" Id="{1391bf86-9235-4963-ac42-c9d006f7dcd2}">
      <Declaration><![CDATA[// Call this to tell if winch are allowed to time out
METHOD PROTECTED _preventWinchTimeOut : BOOL
VAR_INPUT
	CMD : BOOL;
END_VAR
]]></Declaration>
      <Implementation>
        <ST><![CDATA[THIS^._preventTimeout := CMD;]]></ST>
      </Implementation>
    </Method>
    <Property Name="ID" Id="{26c98f61-3f98-4716-b7de-878a94c328aa}">
      <Declaration><![CDATA[// The uniqe winch identificator
{attribute 'TcRpcEnable'}
PROPERTY ID : DINT]]></Declaration>
      <Get Name="Get" Id="{b3aba5e5-3b11-4c6f-b4f3-4400ed2ab6d7}">
        <Declaration><![CDATA[]]></Declaration>
        <Implementation>
          <ST><![CDATA[ID := THIS^.WinchID;]]></ST>
        </Implementation>
      </Get>
    </Property>
    <Method Name="winchDriverStopped" Id="{38e7cbe4-a182-0f1e-2d3b-49e1f96ac18d}">
      <Declaration><![CDATA[{attribute 'TcRpcEnable'}
METHOD winchDriverStopped : BOOL
]]></Declaration>
      <Implementation>
        <ST><![CDATA[
IF _winch <> 0 THEN
	winchDriverStopped :=  _winch.OpState = p6com.P6OpState.STOPPED OR  _winch.OpState = p6com.P6OpState.NOTAVAILABLE ;
ELSE
	winchDriverStopped := FALSE;
END_IF]]></ST>
      </Implementation>
    </Method>
    <Method Name="getVelocityReference" Id="{494dbe75-adb4-01ba-3396-f2feff1d6f0a}">
      <Declaration><![CDATA[{attribute 'TcRpcEnable'}
METHOD getVelocityReference : LREAL
]]></Declaration>
      <Implementation>
        <ST><![CDATA[IF _controlUnitInControl <> 0 THEN
	getVelocityReference := _controlUnitInControl.VelocityReference;
ELSE
	getVelocityReference := 0.0;
END_IF]]></ST>
      </Implementation>
    </Method>
    <Property Name="Name" Id="{4a8a451f-4c80-036c-3875-bb77cd925af3}">
      <Declaration><![CDATA[{attribute 'monitoring' := 'call'}
{attribute 'TcRpcEnable'}
PROPERTY Name : p7type.P6IdName]]></Declaration>
      <Get Name="Get" Id="{26163aeb-1e1f-0d29-158a-37a8eb0abe75}">
        <Declaration><![CDATA[VAR
END_VAR
]]></Declaration>
        <Implementation>
          <ST><![CDATA[IF __ISVALIDREF(configUserWinch) THEN
	Name := configUserWinch.name;
ELSE
	Name := '';	
END_IF]]></ST>
        </Implementation>
      </Get>
    </Property>
    <Property Name="AutoMode" Id="{4cf72355-84df-00b3-3a4c-63565bffa03b}">
      <Declaration><![CDATA[// This property is for the handshaking between user control and winch
PROPERTY AutoMode : BOOL]]></Declaration>
      <Set Name="Set" Id="{a3a466e4-4ef9-07c5-267e-34a1a5532997}">
        <Declaration><![CDATA[]]></Declaration>
        <Implementation>
          <ST><![CDATA[_requestAutoMode := AutoMode;]]></ST>
        </Implementation>
      </Set>
    </Property>
    <Property Name="TorqueRel" Id="{6cea4751-bff2-4c5e-ab35-cd15f316ae84}">
      <Declaration><![CDATA[// Wire torque in %, range 0-1
{attribute 'monitoring':='call'}
{attribute 'TcRpcEnable'}
PROPERTY TorqueRel : LREAL]]></Declaration>
      <Get Name="Get" Id="{8282e735-638e-458e-9da8-b83c04a8b4ed}">
        <Declaration><![CDATA[VAR
END_VAR
]]></Declaration>
        <Implementation>
          <ST><![CDATA[TorqueRel := _winch.TorqueRel;]]></ST>
        </Implementation>
      </Get>
    </Property>
    <Method Name="_reduceSpeedAndTension" Id="{7376c060-6d19-409e-acce-13be2b0d6352}">
      <Declaration><![CDATA[// Call this to tell winch to reduce speed and tension
METHOD PROTECTED _reduceSpeedAndTension : BOOL
VAR_INPUT
	CMD : BOOL;
END_VAR
]]></Declaration>
      <Implementation>
        <ST><![CDATA[THIS^._reducedSpeedAndTension := CMD;]]></ST>
      </Implementation>
    </Method>
    <Method Name="_handleMotorCooling" Id="{788ab5e0-b4fb-4edc-9e51-10d60ea98271}">
      <Declaration><![CDATA[METHOD _handleMotorCooling : BOOL
VAR_INPUT
END_VAR
]]></Declaration>
      <Implementation>
        <ST><![CDATA[// If no motor cooling just skip the rest...
IF motorCooling = 0 THEN
	_coolingAvailable := FALSE;
	RETURN;
END_IF

  
IF	(_State = p7type.UserWinchStates.EMERGENCYSTOP) OR
	(winch.OpState = p7type.P6OpState.RUN) THEN
	motorCooling.requestCooling();
END_IF

_coolingAvailable := motorCooling.CoolingAvailable;
	]]></ST>
      </Implementation>
    </Method>
    <Property Name="OpState" Id="{78c85503-a188-090e-1c88-a8451d074cd3}">
      <Declaration><![CDATA[{attribute 'monitoring' := 'call'}
(* This is the unified state of the state of operation *)
{attribute 'TcRpcEnable'}
PROPERTY OpState : p6com.P6OpState]]></Declaration>
      <Get Name="Get" Id="{6a009820-ad0f-0a61-203c-c2bea97eb285}">
        <Declaration><![CDATA[
]]></Declaration>
        <Implementation>
          <ST><![CDATA[OpState := _opstate;


]]></ST>
        </Implementation>
      </Get>
    </Property>
    <Property Name="ReduceConstantTorqueSignal" Id="{7f770e4f-3bb5-0d29-1daa-8bc2bee53efa}">
      <Declaration><![CDATA[{attribute 'monitoring':='call'}
{attribute 'TcRpcEnable'}
PROPERTY PUBLIC ReduceConstantTorqueSignal : BOOL // external signal to reduce CT.]]></Declaration>
      <Set Name="Set" Id="{4199fbe1-06cc-07bd-0420-62fc2be87ac9}">
        <Declaration><![CDATA[VAR
END_VAR
]]></Declaration>
        <Implementation>
          <ST><![CDATA[_reduceConstantTorque := ReduceConstantTorqueSignal;]]></ST>
        </Implementation>
      </Set>
      <Get Name="Get" Id="{73cb33d0-1e8c-0f06-02a8-82ca7c57f956}">
        <Declaration><![CDATA[
VAR
END_VAR
]]></Declaration>
        <Implementation>
          <ST><![CDATA[ReduceConstantTorqueSignal := _reduceConstantTorque;]]></ST>
        </Implementation>
      </Get>
    </Property>
    <Property Name="SpeedMax" Id="{81c757b5-8d74-47e2-8cc1-baab7dbd389f}">
      <Declaration><![CDATA[// Maximum rotation speed in RPM for this winch
{attribute 'monitoring':='call'}
{attribute 'TcRpcEnable'}
PROPERTY SpeedMax : LREAL]]></Declaration>
      <Get Name="Get" Id="{96f1adfa-f614-4fba-9fea-99875fafebed}">
        <Declaration><![CDATA[VAR
END_VAR
]]></Declaration>
        <Implementation>
          <ST><![CDATA[SpeedMax := _winch.SpeedMax;]]></ST>
        </Implementation>
      </Get>
    </Property>
    <Property Name="ControlCanBeReleased" Id="{8ed5d772-848a-435e-b1d5-2302ffa11e4d}">
      <Declaration><![CDATA[// Control of winch from control unit can be released. Means that winch is not moving, etc. 
// TRUE if winch is not moving
{attribute 'TcRpcEnable'}
PROPERTY ControlCanBeReleased : BOOL]]></Declaration>
      <Get Name="Get" Id="{e42791d2-a810-44ba-9f85-d3921aac7c13}">
        <Declaration><![CDATA[VAR
END_VAR
]]></Declaration>
        <Implementation>
          <ST><![CDATA[IF configUserWinch.optionControlCanBeReleasedWhileRotating THEN
	ControlCanBeReleased := TRUE;
ELSE
	ControlCanBeReleased := NOT _winch.IsRotating;	
END_IF]]></ST>
        </Implementation>
      </Get>
    </Property>
    <Property Name="State" Id="{98825a0d-9202-4931-8ffe-cb7ecc18dda9}">
      <Declaration><![CDATA[// The current state of the winch
{attribute 'TcRpcEnable'}
PROPERTY State : p7type.UserWinchStates]]></Declaration>
      <Get Name="Get" Id="{975fe280-cbfc-42b6-8a72-1c44548c10c0}">
        <Declaration><![CDATA[VAR
END_VAR
]]></Declaration>
        <Implementation>
          <ST><![CDATA[State := _State;]]></ST>
        </Implementation>
      </Get>
    </Property>
    <Method Name="SetLengthNull" Id="{99078777-8ac5-4209-acde-7a5c1619ae99}">
      <Declaration><![CDATA[// Resets length of wire to 0
{attribute 'TcRpcEnable'}
METHOD SetLengthNull : BOOL
]]></Declaration>
      <Implementation>
        <ST><![CDATA[_winch.setLengthNull();]]></ST>
      </Implementation>
    </Method>
    <Property Name="Speed" Id="{9ec8b4f5-1b7f-4da9-a4a6-c1e78d9796b0}">
      <Declaration><![CDATA[// Winch rotation speed in RPM
{attribute 'monitoring':='call'}
{attribute 'TcRpcEnable'}
PROPERTY Speed : LREAL]]></Declaration>
      <Get Name="Get" Id="{8f0872f7-e999-4c8a-a69f-98002686cc4e}">
        <Declaration><![CDATA[VAR
END_VAR
]]></Declaration>
        <Implementation>
          <ST><![CDATA[Speed := _winch.Speed;]]></ST>
        </Implementation>
      </Get>
    </Property>
    <Property Name="Mode" Id="{a10c212d-01c7-0e43-1563-7be9785f2770}">
      <Declaration><![CDATA[{attribute 'monitoring' := 'call'}
(* This is the unified state of the state of operation *)
{attribute 'TcRpcEnable'}
PROPERTY Mode : p7type.WinchModes]]></Declaration>
      <Get Name="Get" Id="{7050ea41-bd4b-07c5-2aac-d5914becc02f}">
        <Declaration><![CDATA[
]]></Declaration>
        <Implementation>
          <ST><![CDATA[Mode := _winchMode;


]]></ST>
        </Implementation>
      </Get>
    </Property>
    <Property Name="InhibitManualRotation" Id="{b5e9ebe5-a932-0860-24df-263f1abb5dbc}">
      <Declaration><![CDATA[// Can be used externally to prevent movement on active winch in manual.
{attribute 'monitoring':='call'}
{attribute 'TcRpcEnable'}
PROPERTY InhibitManualRotation : bool]]></Declaration>
      <Set Name="Set" Id="{b1c07455-4cf5-0423-3dd5-e12123502514}">
        <Declaration><![CDATA[VAR
END_VAR
]]></Declaration>
        <Implementation>
          <ST><![CDATA[_inhibitManualRotation := InhibitManualRotation;]]></ST>
        </Implementation>
      </Set>
      <Get Name="Get" Id="{c3a47466-5c83-0b1b-0bea-6c812a2e3324}">
        <Declaration><![CDATA[VAR
END_VAR
]]></Declaration>
        <Implementation>
          <ST><![CDATA[InhibitManualRotation := _inhibitManualRotation;]]></ST>
        </Implementation>
      </Get>
    </Property>
    <Property Name="Length" Id="{d0594bf2-26be-46b9-b078-2821da79b938}">
      <Declaration><![CDATA[// Wire length in meters
{attribute 'monitoring':='call'}
{attribute 'TcRpcEnable'}
PROPERTY Length : LREAL]]></Declaration>
      <Get Name="Get" Id="{41c74761-ee64-4949-804c-660da0f3f3b9}">
        <Declaration><![CDATA[VAR
END_VAR
]]></Declaration>
        <Implementation>
          <ST><![CDATA[Length := _winch.Length;]]></ST>
        </Implementation>
      </Get>
    </Property>
    <Property Name="Velocity" Id="{d322a631-98f4-491d-be01-441acbd7a7b6}">
      <Declaration><![CDATA[// Winch velocity in m/sec
{attribute 'monitoring':='call'}
{attribute 'TcRpcEnable'}
PROPERTY Velocity : LREAL]]></Declaration>
      <Get Name="Get" Id="{2913bca7-9d44-4904-993b-3c50d2b64c56}">
        <Declaration><![CDATA[VAR
END_VAR
]]></Declaration>
        <Implementation>
          <ST><![CDATA[Velocity := _winch.Velocity;]]></ST>
        </Implementation>
      </Get>
    </Property>
    <Method Name="_determineWinchManualMode" Id="{d589115c-368d-49de-98c6-ea0df5041d1f}">
      <Declaration><![CDATA[// Determine winch mode requested from control unit
// this method wil be overridden by prseSeine and Gear winch.
METHOD PROTECTED _determineWinchManualMode : BOOL
]]></Declaration>
      <Implementation>
        <ST><![CDATA[IF THIS^._controlUnitInControl <> 0 THEN	
	//IF NOT THIS^._winch.IsRotating THEN
		THIS^._winchManualMode := THIS^._controlUnitInControl.RequestedWinchMode;
	//END_IF
ELSE
	THIS^._winchManualMode := WinchManualModes.NORMAL;
END_IF
]]></ST>
      </Implementation>
    </Method>
    <Method Name="_controlParkingBrakes" Id="{d695669b-2e48-4924-b29b-7e12c51fbbec}">
      <Declaration><![CDATA[// Code to handle parking brakes. 
// Override in extended winch types, like purse seine 
METHOD _controlParkingBrakes : BOOL

]]></Declaration>
      <Implementation>
        <ST><![CDATA[// Add code here when this should be implemented for baseUserWinches
IO_Out.parkingBrakeLiftInhibit := winch.OpState <> p7type.P6OpState.RUN;

]]></ST>
      </Implementation>
    </Method>
    <Property Name="Torque" Id="{d8a3e7c4-c661-4ad3-9a97-fd61694f5f88}">
      <Declaration><![CDATA[// Wire torque in Nm
{attribute 'monitoring':='call'}
{attribute 'TcRpcEnable'}
PROPERTY Torque : LREAL]]></Declaration>
      <Get Name="Get" Id="{88a62b5d-cd18-4c9e-9ac1-5b73eac708d3}">
        <Declaration><![CDATA[VAR
END_VAR
]]></Declaration>
        <Implementation>
          <ST><![CDATA[Torque := _winch.Torque;]]></ST>
        </Implementation>
      </Get>
    </Property>
    <Property Name="Tension" Id="{db7fe8cb-a505-42e4-b0a4-a48679375ff3}">
      <Declaration><![CDATA[// Wire tension in Kg
{attribute 'monitoring':='call'}
{attribute 'TcRpcEnable'}
PROPERTY Tension : LREAL]]></Declaration>
      <Get Name="Get" Id="{fef1dabe-6253-4472-b2ad-40a52c503e52}">
        <Declaration><![CDATA[VAR
END_VAR
]]></Declaration>
        <Implementation>
          <ST><![CDATA[Tension := _winch.Tension;]]></ST>
        </Implementation>
      </Get>
    </Property>
    <Method Name="AssignControlUnitInControl" Id="{de95e3bd-367b-43df-af52-8f59082b3cd2}">
      <Declaration><![CDATA[(* Assigns the control unit that is granted control bu ControlUnitMux to _controlUnitInControl *)

METHOD AssignControlUnitInControl : BOOL
VAR_INPUT
	ControlUnitInControl : p7type.IBaseControlUnit;
END_VAR
]]></Declaration>
      <Implementation>
        <ST><![CDATA[IF ControlUnitInControl <> 0 THEN
	IF ControlUnitInControl = _controlUnitInControl THEN
		AssignControlUnitInControl := FALSE;
		RETURN;
	ELSIF (__QUERYINTERFACE(ControlUnitInControl, _controlUnitInControl)) THEN
    	AssignControlUnitInControl := TRUE;
		_newControlUnitAssigned := TRUE;
	ELSE
    	AssignControlUnitInControl := FALSE;
	END_IF
ELSE
	_controlUnitInControl := 0;
	AssignControlUnitInControl := TRUE;
END_IF 
]]></ST>
      </Implementation>
    </Method>
    <Property Name="BlockStopSignal" Id="{e3afff84-13ec-0833-3577-996c7c0fa76b}">
      <Declaration><![CDATA[{attribute 'monitoring':='call'}
{attribute 'TcRpcEnable'}
PROPERTY PUBLIC BlockStopSignal : BOOL // external block stop signal]]></Declaration>
      <Set Name="Set" Id="{77d00f0c-be6f-0f6b-0c02-b1030cc07949}">
        <Declaration><![CDATA[VAR
END_VAR
]]></Declaration>
        <Implementation>
          <ST><![CDATA[_blockStop := BlockStopSignal;]]></ST>
        </Implementation>
      </Set>
      <Get Name="Get" Id="{83bd4ebe-816e-0af4-320d-86b8c5e5386c}">
        <Declaration><![CDATA[
VAR
END_VAR
]]></Declaration>
        <Implementation>
          <ST><![CDATA[BlockStopSignal := _blockStop ;]]></ST>
        </Implementation>
      </Get>
    </Property>
    <Property Name="IsReadyToActivate" Id="{ea283d61-9a48-44df-b6dd-2e1cc35d0935}">
      <Declaration><![CDATA[// True when winch is ready to be activated
{attribute 'monitoring':='call'}
{attribute 'TcRpcEnable'}
PROPERTY IsReadyToActivate : BOOL]]></Declaration>
      <Get Name="Get" Id="{ec5d7f69-62f3-493f-9151-bb859b3ee9ad}">
        <Declaration><![CDATA[VAR
END_VAR
]]></Declaration>
        <Implementation>
          <ST><![CDATA[IsReadyToActivate := _winch.isReadyToActivate AND Enable;]]></ST>
        </Implementation>
      </Get>
    </Property>
    <Property Name="SafetyDistance" Id="{eab5f96a-38fa-0038-3f7a-d2ac0aad48f9}">
      <Declaration><![CDATA[{attribute 'monitoring' := 'call'}
{attribute 'TcRpcEnable'}
PROPERTY SafetyDistance : LREAL]]></Declaration>
      <Get Name="Get" Id="{c3abeea5-c19f-0c31-2ba4-29aa97e54172}">
        <Declaration><![CDATA[VAR
END_VAR
]]></Declaration>
        <Implementation>
          <ST><![CDATA[IF __ISVALIDREF(configUserWinch) THEN
	SafetyDistance := configUserWinch.safetyDistance;
ELSE
	SafetyDistance := 25;	
END_IF]]></ST>
        </Implementation>
      </Get>
    </Property>
    <Property Name="BoostAllowed" Id="{ecdf6d29-59d5-4e94-8055-ae3883dc1a58}">
      <Declaration><![CDATA[// True when winch is allowed to boost
{attribute 'monitoring':='call'}
{attribute 'TcRpcEnable'}
PROPERTY BoostAllowed : BOOL]]></Declaration>
      <Get Name="Get" Id="{3b36693a-427f-42c9-839f-b0104493f6d4}">
        <Declaration><![CDATA[VAR
END_VAR
]]></Declaration>
        <Implementation>
          <ST><![CDATA[BoostAllowed := FALSE;]]></ST>
        </Implementation>
      </Get>
    </Property>
    <Method Name="_handleGearCooling" Id="{fbc30276-6e9a-4822-8940-df80f2881730}">
      <Declaration><![CDATA[METHOD _handleGearCooling : BOOL
VAR_INPUT
END_VAR
]]></Declaration>
      <Implementation>
        <ST><![CDATA[// If no gear cooling just skip the rest...
IF gearCooling = 0 THEN
	RETURN;
END_IF


IF (winch.OpState = p7type.P6OpState.RUN) THEN
	gearCooling.requestCooling();
END_IF
	
]]></ST>
      </Implementation>
    </Method>
  </POU>
</TcPlcObject>