﻿<?xml version="1.0" encoding="utf-8"?>
<TcPlcObject Version="1.1.0.1">
  <POU Name="P7" Id="{08a895d9-f891-47db-be0d-c5cf176da0a1}" SpecialFunc="None">
    <Declaration><![CDATA[FUNCTION_BLOCK P7
VAR	
	Config 			: REFERENCE TO Config;
	OpValues		: REFERENCE TO OpValues;
	state			: P6StateMachine := P6StateMachine.BOOT;
	N				: DINT;

	Reboot			: NT_Reboot;
	startSavePData	: BOOL;
	doReboot		: BOOL := FALSE;
	restartTwincat	: BOOL;
	twincatRestart	: TC_Restart; 
	
	{attribute 'hide'}EnteredRun : R_TRIG;
END_VAR]]></Declaration>
    <Implementation>
      <ST><![CDATA[]]></ST>
    </Implementation>
    <Method Name="update" Id="{05c529f4-4a5d-42b6-b5d7-b2ae04a0a1a2}">
      <Declaration><![CDATA[METHOD update : BOOL
VAR_INPUT
	Config 		: REFERENCE TO Config;
	OpValues	: REFERENCE TO OpValues;
END_VAR
VAR
	InRun : BOOL;
	firstRunstateCycle : BOOL := TRUE;
END_VAR

VAR_INST
	count1 : UINT;
	count2 : UINT;
	count3 : UINT;
	
END_VAR]]></Declaration>
      <Implementation>
        <ST><![CDATA[THIS^.Config REF= Config;
THIS^.OpValues REF= opvalues;

CASE state OF
	P6StateMachine.BOOT: 
		InRun := FALSE;
		state := P6StateMachine.PERSISTENT_DATA;
		
		
	P6StateMachine.PERSISTENT_DATA:
		InRun := FALSE;
		// Do not save persistent data on boot! 
		//( IF savePersistentData() THEN
			state := P6StateMachine.INIT; 
		//END_IF

	P6StateMachine.INIT: 
		InRun := FALSE;
		// This is the important part for initialisation. 
		IF Config.isConfigured THEN
			initConfig();
			state := P6StateMachine.RUN;
		END_IF

	P6StateMachine.RUN:
		InRun := TRUE;
		CT.timekeeping();
		EnteredRun(CLK := InRun);		// prepopulate interface
		THIS^._testCode();			// just for test
		THIS^.updateMisc();
		
		IF firstRunstateCycle THEN		// this is the original location, but we want to run this after all winch updates.... 
			THIS^.Inverters();
			firstRunstateCycle := FALSE;
		END_IF
		THIS^.updatePower();
		THIS^.updateBrakeHPU();
		THIS^.updateDeckHPU();
		THIS^.updateCooling();
		THIS^.Buzzer();
		THIS^.updateRadio();
		
		(*Handling*)
		THIS^.updateKN75();
		THIS^.updateCtdDavid();
		THIS^.updateAframe();
		THIS^.updateOHC();
		
		(*Winch*)
		THIS^.updateAHC();
		THIS^.update_StorageDrum();
		THIS^.update_CTD();
		THIS^.update_TRW();
		THIS^.updateSlackWireCompensator();
		
		THIS^.Inverters();			// added here to upate the vfd`s after winch code

		THIS^.PanelMux();
		
		THIS^.updateModbus();
		THIS^.updateOuthauler();
		Obj.udpHandler(config := Config.UDP); 	// Send logger data to Mbari
		CT.houseKeeping();
		CT.UDPdataCollection();				// fetch data to send.
		CT.udpHandlerFast();				// send debug data to laptop
		
				
		IF NOT config.isConfigured THEN
			state := P6StateMachine.BOOT;			
		ELSIF startSavePData THEN
			IF savePersistentData() THEN
				startSavePData := FALSE;
			END_IF 
		END_IF
		ObjHMI.readyForHMI := TRUE;		// everything should be OK by now.
		SystemStatus();
	
END_CASE

]]></ST>
      </Implementation>
    </Method>
    <Method Name="updateBrakeHPU" Id="{0a8b9d63-c301-4a87-b41b-eb1688fea20c}">
      <Declaration><![CDATA[METHOD updateBrakeHPU : BOOL

]]></Declaration>
      <Implementation>
        <ST><![CDATA[IF NOT config.IsConfigured THEN
	RETURN;
END_IF

objBrakeHPU.BrakeHPU1(
	ID := EBrakeHPU.HPU,
	Config := Config.brakeHPU,
	IO_In := objBrakeHPU.brakeHPU1Io_in,
	IO_Out := objBrakeHPU.brakeHPU1Io_out,
	OpValues := OpValues.brakeHPU,
	EmergencyStop := ObjGeneral.estopObject.Activated
);

// added to let HMI start brake HPU.
IF objBrakeHPU.manualStart_HPU1 THEN
	objBrakeHPU.BrakeHPU1.setActive();
	
END_IF


]]></ST>
      </Implementation>
    </Method>
    <Method Name="Inverters" Id="{0ef86dac-a201-423e-a997-d6237a77e045}">
      <Declaration><![CDATA[METHOD Inverters : BOOL
VAR 
	N : DINT;
END_VAR]]></Declaration>
      <Implementation>
        <ST><![CDATA[IF NOT config.isConfigured THEN
	RETURN;
END_IF

// has to be here to make any sense....
ObjDriveTrain.allInvertersAreDown := TRUE;
FOR N := 0 TO Param.noInverters - 1 DO
	ObjDriveTrain.acs880[N](
		Config 		:= config.inverter[N], 
		opvalues 	:= opvalues.inverters[N],
		IO_in 		:= IOin.inverters[N],
		IO_out 		:= IOout.inverters[N]
	);
	config.inverter[N].ID := N;
	
	// ObjDriveTrain.allInvertersAreDown := TRUE;
	IF ObjDriveTrain.acs880[N].State = p7type.P6State.OP AND N < (EInv.ARRAY_SIZE) THEN
		ObjDriveTrain.allInvertersAreDown := FALSE;
	END_IF 
END_FOR

]]></ST>
      </Implementation>
    </Method>
    <Method Name="update_StorageDrum" Id="{0f8c4524-8d95-4861-8b1f-9544a17b2e2a}">
      <Declaration><![CDATA[METHOD update_StorageDrum : BOOL
VAR_INST
	hasStarted : BOOL;
	//setOffset : BOOL;
END_VAR
VAR CONSTANT
	DIM_OUTPUT : p6manualDevices.ConfigDimmableOutputs := (output:= [TRUE, TRUE, TRUE, TRUE]);
END_VAR

VAR_INST
	counter : UDINT;
	errCnt : UDINT;
	rev : LREAL ;
END_VAR]]></Declaration>
      <Implementation>
        <ST><![CDATA[IF NOT config.isConfigured THEN
	RETURN;
END_IF

IF NOT hasStarted THEN
	hasStarted := TRUE;
	
	config.drive[EDrv.STORAGEDRUM].ID := EDrv.STORAGEDRUM;
	
	gvlStorageDrum01.drive
		.resetService()
		.attach(ObjDriveTrain.acs880[EInv.STORAGEDRUM_INV0]);

	gvlStorageDrum01.spool_drive	//Spool have no Mux
			.resetService()
			.attach(ObjDriveTrain.acs880[EInv.STORAGEDRUM_LEV01_INV0]);	//Inv for spool

	ObjDriveTrain.IUserWinches[eWinch.STORAGEDRUM] := gvlStorageDrum01.winch; 
	ObjDriveTrain.arrayISpool[espool.STORAGEDRUM01] := gvlStorageDrum01.spool;

	ObjManDev.ICtrlUnits[EPanel.STORAGEDRUM_LOCAL] := gvlStorageDrum01.deckCtrlPanel_WP02;
	gvlStorageDrum01.deckCtrlPanel_WP02.SetSelectedWinch(gvlStorageDrum01.winch);
	
	ObjManDev.ICtrlUnits[EPanel.DUMMY_STORAGEDRUM] := gvlStorageDrum01.dummyStorageControlPanel;
	ObjManDev.ICtrlUnits[EPanel.DUMMY_STORAGEDRUM].SetSelectedWinch(gvlStorageDrum01.winch);
	
	ObjManDev.ICtrlUnits[EPanel.STORAGEDRUM_HMI] := gvlStorageDrum01.ctrlU_HMI_STORAGEDRUM01;
	gvlStorageDrum01.ctrlU_HMI_STORAGEDRUM01.SetSelectedWinch(gvlStorageDrum01.winch);
	
	//************************* first run direction *****************
	gvlStorageDrum01.drive(		//winch
	Config 		:= config.drive[EDrv.STORAGEDRUM], 
	DriveMux 	:= 0
	);	
	
	ObjDriveTrain.driveInfos[eDrv.STORAGEDRUM](Drive:= gvlStorageDrum01.drive);
	
	gvlStorageDrum01.spool_drive(	//spool
		Config 		:= config.drive[EDrv.SPOOL_STORAGEDRUM], 
		DriveMux 	:= 0,
	);	
	ObjDriveTrain.driveInfos[EDrv.SPOOL_STORAGEDRUM](Drive:= gvlStorageDrum01.spool_drive);
	
	gvlStorageDrum01.eWinch(
		Config 				:= config.EWinch[Ewinch.STORAGEDRUM],
		OpValues 			:= opvalues.ewinch[Ewinch.STORAGEDRUM],
		Drive 				:= gvlStorageDrum01.drive,
		Encoder		 		:= ObjDriveTrain.inverters[EInv.STORAGEDRUM_INV0].getEncoder(0),
		HCController 		:= 0,
		SpoolHeadPosition	:= gvlStorageDrum01.spool.HeadPosition,
		BrakeHPU			:= objBrakeHPU.BrakeHPU1
	);
	
	gvlStorageDrum01.spool(
		ID					:= ESpool.STORAGEDRUM01,
		Config 				:= Config.spool[ESpool.STORAGEDRUM01],
		IO_In 				:= gvlStorageDrum01.spool_io_in,
		OpValues 			:= OpValuesPersistent.opvalues.storageDrum_spool,
		WinchConfig			:= Config.eWinch[Ewinch.STORAGEDRUM],
		Winch 				:= gvlStorageDrum01.eWinch,
		Drive 				:= gvlStorageDrum01.spool_drive,
		Encoder 			:= ObjDriveTrain.inverters[EInv.STORAGEDRUM_LEV01_INV0].getEncoder(0), 
		//EncoderWinch 		:= 0,
		FollowUpSensor 		:= IOin.sensorFollowUpSDrum,
		EmergencyStop		:= objGeneral.estopObject,
	);	
	
	gvlStorageDrum01.winch(
		WinchID			:= Ewinch.STORAGEDRUM,
		IO_In			:= gvlStorageDrum01.winchIo_in,
		IO_Out			:= gvlStorageDrum01.winchIo_out,
		configUserWinch := config.userWinch[Ewinch.STORAGEDRUM],
		Winch 			:= gvlStorageDrum01.eWinch,
		EmergencyStop 	:= objGeneral.estopObject,
		MotorCooling	:= 0,
		GearCooling		:= objCooling.gearCooling
	);
		
	
END_IF

gvlStorageDrum01.spool_drive(	//spool
	Config 		:= config.drive[EDrv.SPOOL_STORAGEDRUM], 
	DriveMux 	:= 0,
);	
ObjDriveTrain.driveInfos[EDrv.SPOOL_STORAGEDRUM](Drive:= gvlStorageDrum01.spool_drive);

gvlStorageDrum01.spool(
	ID					:= ESpool.STORAGEDRUM01,
	Config 				:= Config.spool[ESpool.STORAGEDRUM01],
	IO_In 				:= gvlStorageDrum01.spool_io_in,
	OpValues 			:= OpValuesPersistent.opvalues.storageDrum_spool,
	WinchConfig			:= Config.eWinch[Ewinch.STORAGEDRUM],
	Winch 				:= gvlStorageDrum01.eWinch,
	Drive 				:= gvlStorageDrum01.spool_drive,
	Encoder 			:= ObjDriveTrain.inverters[EInv.STORAGEDRUM_LEV01_INV0].getEncoder(0), 
	//EncoderWinch 		:= 0,
	FollowUpSensor 		:= IOin.sensorFollowUpSDrum,
	EmergencyStop		:= objGeneral.estopObject,
);	

gvlStorageDrum01.winch(
	WinchID			:= Ewinch.STORAGEDRUM,
	IO_In			:= gvlStorageDrum01.winchIo_in,
	IO_Out			:= gvlStorageDrum01.winchIo_out,
	configUserWinch := config.userWinch[Ewinch.STORAGEDRUM],
	Winch 			:= gvlStorageDrum01.eWinch,
	EmergencyStop 	:= objGeneral.estopObject,
	MotorCooling	:= 0,
	GearCooling		:= objCooling.gearCooling
);

gvlStorageDrum01.eWinch(
	Config 				:= config.EWinch[Ewinch.STORAGEDRUM],
	OpValues 			:= opvalues.ewinch[Ewinch.STORAGEDRUM],
	Drive 				:= gvlStorageDrum01.drive,
	Encoder		 		:= ObjDriveTrain.inverters[EInv.STORAGEDRUM_INV0].getEncoder(0),
	HCController 		:= 0,
	SpoolHeadPosition	:= gvlStorageDrum01.spool.HeadPosition,
	BrakeHPU			:= objBrakeHPU.BrakeHPU1
);

gvlStorageDrum01.drive(		//winch
	Config 		:= config.drive[EDrv.STORAGEDRUM], 
	DriveMux 	:= 0
);	
ObjDriveTrain.driveInfos[eDrv.STORAGEDRUM](Drive:= gvlStorageDrum01.drive);

(*Panels*)
gvlStorageDrum01.deckCtrlPanel_WP02.Disable := NOT gvlTractionWinch01.splitModeRequest;
gvlStorageDrum01.deckCtrlPanel_WP02(
	ID					:= EPanel.STORAGEDRUM_LOCAL,
	IO_In				:= gvlStorageDrum01.deckCtrlPanel_WP02_Io_in,
	IO_Out				:= gvlStorageDrum01.deckCtrlPanel_WP02_Io_out,
	controlUnitMux		:= ObjManDev.panelMux,
	masterControl		:= 0,
	emergencyStop		:= objGeneral.estopObject,
	config				:= config.ctrlBaseUnit[EPanel.STORAGEDRUM_LOCAL],
	bridgeControl		:= 0,
	winchSelector		:= 0,
	SplitModeController	:= 0,
	manualSpoolControl	:= gvlStorageDrum01.manSpool_deckCtrl_WP02,
);	

// only used to activate the drum so the SDR can put it in auto.
//gvlStorageDrum01.dummyStorageControlPanel.Disable := NOT gvlTractionWinch01.splitModeRequest;
gvlStorageDrum01.dummyStorageControlPanel(
	ID					:= EPanel.DUMMY_STORAGEDRUM,
	IO_In				:= gvlStorageDrum01.Dummy_Io_in,
	IO_Out				:= gvlStorageDrum01.Dummy_Io_out,
	controlUnitMux		:= ObjManDev.panelMux,
	masterControl		:= 0,
	emergencyStop		:= objGeneral.estopObject,
	config				:= config.ctrlBaseUnit[EPanel.DUMMY_STORAGEDRUM],
	bridgeControl		:= 0,
	winchSelector		:= 0,
	SplitModeController	:= 0,
	// let's keep the manual spooling from the deck CP
	manualSpoolControl	:= 0 //gvlStorageDrum01.manSpool_deckCtrl_WP02,
);	

(*Spool*)
gvlStorageDrum01.manSpool_deckCtrl_WP02(	
	IO_In 	:= gvlStorageDrum01.deckCtrlPanel_WP02_manSpoolIO_In,
	spool 	:= gvlStorageDrum01.spool,
);

(*HMI*)
gvlStorageDrum01.ctrlU_HMI_STORAGEDRUM01(
	ID 						:= EPanel.STORAGEDRUM_HMI,
	IO_In					:= gvlStorageDrum01.HMI_Io_in,
	IO_Out					:= gvlStorageDrum01.HMI_Io_out,
	controlUnitMux			:= ObjManDev.panelMux,
	masterControl			:= 0,
	emergencyStop			:= objGeneral.estopObject,
	config					:= config.ctrlBaseUnit[EPanel.STORAGEDRUM_HMI],
	hmiSystemUnits			:= config.unitsInUse
);

// run code for controller
gvlStorageDrum01.SDR_controller(
		TRW := gvlTractionWinch01.winch,
		SDR := gvlStorageDrum01.winch,
		SDR_ewinch := gvlStorageDrum01.eWinch,
		SWC := gvlSlackWireCompensator.slackWireComp,
		SDR_controlUnit := gvlStorageDrum01.dummyStorageControlPanel,
		splitMode := gvlTractionWinch01.splitModeRequest,
		config := config.TractionWinch[0],
		estop := objGeneral.estopObject,
		brakeHPU := objBrakeHPU.BrakeHPU1
);




]]></ST>
      </Implementation>
    </Method>
    <Method Name="updateDeckHPU" Id="{202169be-b44e-4b34-8561-58a31308c45a}">
      <Declaration><![CDATA[METHOD updateDeckHPU : BOOL
VAR_INST
	autoHPUdeactivate 	: TOF;
	stopTrigger 		: f_trig;
END_VAR

VAR CONSTANT
	autoHPUdeactivateTime : TIME := T#60M;
END_VAR
]]></Declaration>
      <Implementation>
        <ST><![CDATA[IF NOT config.IsConfigured THEN
	RETURN;
END_IF

(*Deck HPU*)
GvlDeckHPU.HPU(
	IO_In := GvlDeckHPU.Io_in, 
	IO_Out := GvlDeckHPU.Io_out, 
	emergencyStop := objGeneral.estopObject
);

// start and stop signals for crane HPU
gvlDeckHPU.HPU.Start :=
	gvlAframe.RadioBase.startHPU()  OR
	gvlCtdDavid.RadioBase.startHPU() OR
	gvlOHC.RadioBase.startHPU() OR
 	gvlAframe.Crane.startHPU OR
	gvlCtdDavid.Crane.startHPU OR
	gvlOHC.Crane.startHPU OR
	gvlKN75.Crane.startHPU;

gvlDeckHPU.HPU.Stop :=
	gvlAframe.RadioBase.stopHPU()  OR
	gvlCtdDavid.RadioBase.stopHPU() OR
	gvlOHC.RadioBase.stopHPU() OR
 	gvlAframe.Crane.StopHPU OR
	gvlCtdDavid.Crane.StopHPU OR
	gvlOHC.Crane.StopHPU OR
	gvlKN75.Crane.StopHPU;

// stop HPU if no cranes are active for some time
autoHPUdeactivate(PT:=autoHPUdeactivateTime, IN :=
	gvlAframe.Crane.Active OR 
	gvlCtdDavid.Crane.Active OR
	gvlOHC.Crane.Active OR
	gvlKN75.Crane.Active
);
stopTrigger(CLK := autoHPUdeactivate.Q);
IF stopTrigger.Q THEN gvlDeckHPU.HPU.Stop := TRUE;
END_IF
	
// Running feedback
gvlAframe.Crane.PumpIsRunning :=  
	gvlDeckHPU.HPU.Pump1_Running OR 
	gvlDeckHPU.HPU.Pump2_Running ;


]]></ST>
      </Implementation>
    </Method>
    <Method Name="updateOuthauler" Id="{2485b626-78df-4e49-9490-07ae652c0c8a}">
      <Declaration><![CDATA[METHOD updateOuthauler : BOOL
VAR_INST
	hasStarted : BOOL;
	
END_VAR
]]></Declaration>
      <Implementation>
        <ST><![CDATA[IF NOT config.isConfigured THEN
	RETURN;
END_IF

IF NOT hasStarted THEN
	hasStarted := TRUE;
	
	gvlOuthauler.drive
		.resetService()
		.attach(ObjDriveTrain.acs880[EInv.OUTHAULER_INV0]);
		
	

END_IF

// run drive instance
gvlOuthauler.drive(		
	Config 		:= config.drive[EDrv.OUTHAULER], 
	DriveMux 	:= 0
); 
// make available for HMI
ObjDriveTrain.driveInfos[EDrv.OUTHAULER](Drive:=gvlOuthauler.drive);

// outhauler object
gvlOuthauler.Outhauler(
	drive := gvlOuthauler.drive,
	config :=  Config.Outhauler,
	OHC :=  gvlOHC.Crane,
	ewinch := gvlTractionWinch01.eWinch,	// to get info from Traction winch
	userWinch := gvlTractionWinch01.winch,
	vfd := ObjDriveTrain.acs880[einv.TRACTIONWINCH_INV0],
	estop := objGeneral.estopObject
);]]></ST>
      </Implementation>
    </Method>
    <Method Name="updateMisc" Id="{2a715629-01c0-4e64-85a0-400819da094d}">
      <Declaration><![CDATA[(*
 Updating various objects not related to winches
*) 
METHOD PRIVATE updateMisc : BOOL
VAR_INST
	ups				: FB_S_UPS_BAPI; 	// For CX52x0 CPU
//	ups				:FB_S_UPS_CX51x0;	// For CX51x0 CPU
	N				: DINT;
	timer			: TON;
END_VAR]]></Declaration>
      <Implementation>
        <ST><![CDATA[// use the UPS

ups(							//5230
	sNetID 			:= '',
	iPLCPort        := 851,
	tTimeout		:= DEFAULT_ADS_TIMEOUT,
	eUpsMode        := eSUPS_WrPersistData_Shutdown,
	ePersistentMode := E_PersistentMode.SPDM_2PASS,
	tRecoverTime    := T#20S
);

//ups							// 5130
//	sNetID 			:= '',
//	iPLCPort        := 851,
//	iUPSPort		:= 16#588,
//	tTimeout		:= DEFAULT_ADS_TIMEOUT,
//	eUpsMode        := eSUPS_WrPersistData_Shutdown,
//	ePersistentMode := E_PersistentMode.SPDM_2PASS,
//	tRecoverTime    := T#20S
//);


// Reboot
Reboot(
	NetID			:= '',
	Delay			:= 1,
	Start			:= ObjHMI.doReboot,
	TMOut			:= T#10S
);

(*
twincatRestart(
	NETID := '',
	RESTART := objHMI.doReboot,
	TMOUT := T#10S
);
*)	

(*Alarm*)
Obj.alarmCollector.ConfirmAlarms := IO.confirmAlarm1 OR IO.confirmAlarm2 OR 
	gvlTractionWinch01.bridgeCtrlPanel_CP01_Io_in.buzzerAlarmReset OR 
	gvlCtd01.bridgeCtrlPanel_CP02_Io_in.buzzerAlarmReset;
Obj.alarmCollector();		

// ABB wants inverted signals
IO.criticalAlarm := NOT Obj.alarmCollector.AlarmCritical;
IO.warningAlarm := NOT Obj.alarmCollector.AlarmWarning;

IO.Alarm := Obj.alarmCollector.AlarmCritical OR Obj.alarmCollector.AlarmWarning;

// send alarm bit to all panels
timer(IN:=NOT timer.Q, PT:=T#1S);
IF timer.Q THEN
	FOR N :=0 TO Param.noCtrlUnit-1 DO
		IF ObjManDev.ICtrlUnits[N]<> 0 THEN 
			ObjManDev.ICtrlUnits[N].Alarm(IO.Alarm);
		END_IF
	END_FOR
END_IF

//ICtrlUnits					: ARRAY[0..Param.noCtrlUnit-1] OF p6manualDevices.IBaseControlUnit;
objManDev.CrtlUnitMuxHMI(ctrlUnits := objManDev.ICtrlUnits);




]]></ST>
      </Implementation>
    </Method>
    <Method Name="Buzzer" Id="{36b818ea-df70-4099-aa92-852eba06e718}">
      <Declaration><![CDATA[METHOD Buzzer : BOOL
VAR_INST
	autoSilence : TON ;
END_VAR]]></Declaration>
      <Implementation>
        <ST><![CDATA[ObjManDev.buzzer(NewAlarmActive:=IO.Alarm);

autoSilence(IN:= objManDev.buzzer.BuzzerSignal,PT := T#10S);

IF autoSilence.Q THEN
	objManDev.buzzer.SilenceBuzzer();
END_IF


]]></ST>
      </Implementation>
    </Method>
    <Method Name="updateCooling" Id="{3d7ec78d-f22a-44b0-9e0e-7442679abcb1}">
      <Declaration><![CDATA[METHOD updateCooling : BOOL
VAR_INST
	started : BOOL;
	inverters	  				: ARRAY[0..1] OF p7elec.IInverter;
	MotorCoolingStartTimer 		: TON;
	MotorCoolingStopTimer 		: TOF;
	SelectPump2					: BOOL;
	oilLevelAlarm				: p6com.AlarmDigital(TC_Events.LibHydraulicEventClass.HPU_LevelSwitch);
	oilTempAlarm				: p6com.AlarmDigital(TC_Events.LibHydraulicEventClass.HPU_CriticalTemp);
END_VAR
]]></Declaration>
      <Implementation>
        <ST><![CDATA[IF NOT config.IsConfigured THEN
	RETURN;
END_IF

oilLevelAlarm(ID := 2 ,IDname := 'Gear cooling HPU', value := NOT ObjCooling.gearCoolingCtrlIo_in.oilLevel, TimeSpan := T#2S,);
oilTempAlarm(ID := 2 ,IDname := 'Gear cooling HPU', value := NOT ObjCooling.gearCoolingCtrlIo_in.highOilTemperature, TimeSpan := T#2S,);

// will alternate every day 
SelectPump2 := ((DATE_TO_DINT(TIME_TO_DATE(TIME()))/3600/24)MOD 2)=0;


//CurrentTime := TIME();
//currentDate := TIME_TO_DATE(CurrentTime);
//iDate  		:= DATE_TO_DINT(currentDate)/3600/24;
//evenDay		:= (iDate MOD 2) = 0 ;

IF SelectPump2 THEN
	objCooling.gearCoolingCtrlIo_outREF REF= objCooling.gearCoolingCtrlIo_out2;
	objCooling.gearCoolingCtrlIo_out.pumpRun := FALSE;
ELSE
	objCooling.gearCoolingCtrlIo_outREF REF= objCooling.gearCoolingCtrlIo_out;
	objCooling.gearCoolingCtrlIo_out2.pumpRun := FALSE;
END_IF

// if one pump is running, open cooling valve
ObjCooling.waterCoolingValve := objCooling.gearCoolingCtrlIo_outREF.pumpRun ;

// both inputs must be high for oil filter alarm to be OK. Library code only uses 'oilFilter_PressureOK', so 'oilFilter2_PressureOK' must be added to the mix
objCooling.gearCoolingCtrlIo_in.oilFilter_PressureOK :=  TRUE; //  No gear cooling filter alarms on Mbari! // objCooling.gearCoolingCtrlIo_in.oilFilter_PressureOK AND objCooling.gearCoolingCtrlIo_in.oilFilter2_PressureOK;

ObjCooling.gearCoolingController(
	Id 			:= 0,
	Name		:= 'Gear Cooling Control',
	Config 		:= ConfigPersistent.Config.gearCoolingController,
	IO_In		:= objCooling.gearCoolingCtrlIo_in,
	IO_Out		:= objCooling.gearCoolingCtrlIo_outREF,
	Pump		:= 0, //ObjCooling.gearCoolingMotor1,		// not in use in FB
	opvalues 	:= OpValuesPersistent.opvalues.gearCooling,
	EmergencyStop := objGeneral.estopObject,
);

ObjCooling.gearCooling(
	ID := 0,
	config := ConfigPersistent.Config.gearCoolingWinch,
	IO_In := ObjCooling.gearCoolingIo_in,
	Controller := ObjCooling.gearCoolingController
);

// crazy hack just to get hours counting. p7elec.motor is a stupid object!
ObjCooling.gearCoolingMotor1.Active := objCooling.gearCoolingCtrlIo_out.pumpRun  OR (objCooling.manualStart_HPU_gearCooling AND NOT SelectPump2 );
ObjCooling.gearCoolingMotor2.Active := objCooling.gearCoolingCtrlIo_out2.pumpRun OR (objCooling.manualStart_HPU_gearCooling AND SelectPump2 ) ;

ObjCooling.gearCoolingMotor1(
	OpValue := OpValuesPersistent.opvalues.gearcoolingMotor1,
	TempSensor := 0
);
ObjCooling.gearCoolingMotor2(
	OpValue := OpValuesPersistent.opvalues.gearcoolingMotor2,
	TempSensor := 0,
);
	
ObjCooling.gearCoolingController.Inhibit := ObjDriveTrain.allInvertersAreDown;
]]></ST>
      </Implementation>
    </Method>
    <Method Name="updateSlackWireCompensator" Id="{4405dbab-e394-4fae-9e59-28492ccc7d72}">
      <Declaration><![CDATA[METHOD updateSlackWireCompensator : BOOL
VAR_INST
	hasStarted : BOOL;
	_regulatorOutput	: LREAL;
END_VAR
]]></Declaration>
      <Implementation>
        <ST><![CDATA[IF NOT config.isConfigured THEN
	RETURN;
END_IF

IF NOT hasStarted THEN
	hasStarted := TRUE;
END_IF

gvlSlackWireCompensator.slackWireComp(

	Config				:= ConfigPersistent.Config.slackWire[0],
	IO_In 				:= gvlSlackWireCompensator.io_in,
	IO_Out				:= gvlSlackWireCompensator.io_out,
	EmergencyStop 		:= objGeneral.estopObject,

	supplyPressure		:= objBrakeHPU.BrakeHPU1.Pressure,
);]]></ST>
      </Implementation>
    </Method>
    <Method Name="initConfig" Id="{45ef43c2-9298-42d9-bee7-44f5b4cf9af0}">
      <Declaration><![CDATA[
METHOD PRIVATE initConfig : BOOL
]]></Declaration>
      <Implementation>
        <ST><![CDATA[IF NOT config.IsConfigured THEN
	RETURN;
END_IF

// assign VFD's to inverter array and add ID number
FOR N := 0 TO Param.noInverters-1 DO	
	ObjDriveTrain.inverters[N] := ObjDriveTrain.acs880[N];
	config.inverter[N].ID := N;
END_FOR

ObjPower.IGBT_TA1
	.resetServices()
	.attach(ObjDriveTrain.ACS880[EInv.STORAGEDRUM_INV0])
	.attach(ObjDriveTrain.ACS880[EInv.STORAGEDRUM_LEV01_INV0])
	.attach(ObjDriveTrain.ACS880[EInv.CTD_INV0])
	.attach(ObjDriveTrain.ACS880[EInv.CTD_LEV01_INV0])
	.attach(ObjDriveTrain.ACS880[EInv.TRACTIONWINCH_INV0])
	.attach(ObjDriveTrain.ACS880[EInv.TRACTIONWINCH_INV1])
	.attach(ObjDriveTrain.ACS880[EInv.OUTHAULER_INV0]);
	

// add ID numbers to ewinch and drive config objects
FOR N := 0 TO Param.noDrives -1 DO
	config.drive[N].ID := N;
END_FOR
FOR N := 0 TO Param.noWinch -1 DO
	config.eWinch[N].ID := N;
END_FOR

//arrayISpool				   	: ARRAY[0..Param.noSpool-1] OF p7type.ISpool; // Used by HMI
ObjManDev.SpoolAccessHMI(Spool := ObjDriveTrain.arrayISpool);

///inverters 					: p7elec.InverterGroup;
ObjManDev.InvertersAccessHMI(Inverter := ObjDriveTrain.inverters);




]]></ST>
      </Implementation>
    </Method>
    <Method Name="updateAframe" Id="{5ccf2c0b-4540-4df7-83c8-26fb4b07c395}">
      <Declaration><![CDATA[METHOD updateAframe : BOOL
(*no control unit mux... make a local one by having crane controller point to a panel interface, then have one off these panels point to that interface*)
VAR_INST
	Prepopulate : R_TRIG;
END_VAR]]></Declaration>
      <Implementation>
        <ST><![CDATA[IF NOT config.isConfigured THEN
	RETURN;
END_IF

IF EnteredRun.Q THEN//prepopulate
	Objmandev.AframePanel := gvlaframe.Radio_Panel;
END_IF


(*Deck Panel*)
gvlaframe.Deck_Panel(
	_id:= HPanel.Deck_Aframe, 
	emergencyStop:= objGeneral.estopObject, 
	Equipment:= gvlAframe.Crane, 
	Config:= Config.DeckPanelAframe, 
	IO_In:= gvlaframe.Deck_PanelIO_In, 
	IO_Out:= gvlaframe.Deck_PanelIO_Out
);

(*Radio Panel*)
gvlaframe.Radio_Panel(
	_id:= HPanel.Radio_Aframe, 
	Config:= Config.RadioPanelAframe, 
	IO_In:= gvlAframe.Radio_PanelIO_In, 
	IO_Out:= gvlAframe.Radio_PanelIO_Out, 
	emergencyStop:= objGeneral.estopObject,
	Equipment:= gvlAframe.Crane,  
	HBCIO_Out:= gvlAframe.RadioPanelIO_Out, 
	HBCIO_In:= gvlAframe.RadioPanelIO_In, 
	RadioBase:= gvlAframe.RadioBase
);

(*Panel selection*)
IF gvlaframe.Deck_Panel.EventActivateButton AND NOT gvlAframe.Radio_Panel.InControl THEN
	Objmandev.AframePanel := gvlaframe.Deck_Panel;
ELSIF gvlaframe.Radio_Panel.EventActivateButton AND NOT gvlAframe.Deck_Panel.InControl THEN
	Objmandev.AframePanel := gvlaframe.Radio_Panel;
END_IF

(*Crane Controller*)
gvlAframe.Crane(
	_id:= HDrv.Aframe, 
	emergencyStop:= objGeneral.estopObject, 
	Config:= config.CtrlAframe, 
	Panel := Objmandev.AframePanel, //gvlaframe.Radio_Panel,
	IO_In:= gvlaframe.HandlingIo_in, 
	IO_Out:= gvlaframe.HandlingIo_Out
);

(*Calibrating finished*)
IF gvlAframe.Crane.SavePdata THEN
	startSavePData := TRUE;
END_IF


]]></ST>
      </Implementation>
    </Method>
    <Method Name="updatePower" Id="{7d93a340-3817-426c-abc1-40cf9829606f}">
      <Declaration><![CDATA[METHOD updatePower : BOOL
VAR_INST
END_VAR
VAR
	_pmsStbdStartRequest 	: BOOL;
	_pmsPortStartRequest 	: BOOL;
	_pmsCommonStartRequest 	: BOOL;
	
END_VAR
VAR_INST
	PowerUsedOrRegen 		: LREAL;
END_VAR
]]></Declaration>
      <Implementation>
        <ST><![CDATA[IF config.IsConfigured THEN

	objPower.groundFault();
	
	ObjPower.IGBT_TA1(
		Config			:= config.igbt_TA1,
		OpValues		:= opValues.igbt_TA1,
		IO_In 			:= IOIn.igbt_TA1,
		IO_Out			:= IOout.igbt_TA1  	
	);
	
	objPower.PMS_Vessel.PowerUsage := ObjPower.IGBT_TA1.Power;
	objPower.PMS_Vessel.PowerRegenUsage := ObjPower.IGBT_TA1.PowerRegen;
		
	objPower.PMS_Vessel(
		Config 				  := ConfigPersistent.Config.PMSInterface,
		IO_In  				  := objPower.pmsVesselIo_in,
		IO_Out 				  := objPower.pmsVesselIo_out,
		//PowerAvailableSensor  := IOin.sensorPowerAvailable,
		//PowerRegenLimitSensor := IOin.sensorPowerRegenLimit,
		//PowerUsageOut		  := objPower.PowerUsage,
		PMS					  := objPower.PMS
	);
	
	objPower.PMS(
		Config := ConfigPersistent.Config.PMS,
		PMSvessel := objPower.PMS_Vessel,
	);
	
//	objPower.PowerUsage(
//       IO_Out := objPower.PowerUsedToABB,
//       ValueMax := 225,
//       ValueMin := -225,
//   	);
	
	// pick the largest number and send to ABB /PMS
//	IF ObjPower.IGBT_TA1.Power > ABS(ObjPower.IGBT_TA1.PowerRegen) THEN
//		PowerUsedOrRegen := ObjPower.IGBT_TA1.Power;
//	ELSE
//		PowerUsedOrRegen := - ABS(ObjPower.IGBT_TA1.PowerRegen);
//	END_IF
   
//   // signal to analog output
//   objPower.PowerUsage.Value :=  PowerUsedOrRegen;
   // system running
	ObjPower.SystemActive := ObjPower.IGBT_TA1.OpState = P6OpState.RUN;

END_IF;

]]></ST>
      </Implementation>
    </Method>
    <Method Name="_testCode" Id="{834fb006-60af-4916-9a81-433024ed8061}">
      <Declaration><![CDATA[METHOD _testCode : BOOL
VAR_INST
 	firstscan : BOOL := TRUE;
END_VAR
]]></Declaration>
      <Implementation>
        <ST><![CDATA[//GVL.mb_Input_Registers[5] := TIME_TO_WORD(TIME()) ;
IF firstscan THEN
	firstscan :=FALSE;
	RETURN;
END_IF

IF  ADR(gvlCtd01.Sheavesensor) <> 0 THEN
	IF objManDev.SelectedSheaveSensorIndexHMI = 0 THEN
		objManDev.SheaveSensorHMI REF= gvlCtd01.Sheavesensor ;
	ELSE
		objManDev.SheaveSensorHMI REF= gvlTractionWinch01.Sheavesensor;
	END_IF
ELSE
	DebugMessage('Reference to SheaveSensor is missing','','');
END_IF

IF  ADR(gvlCtd01.spool) <> 0 AND  ADR(gvlStorageDrum01.spool) <> 0 THEN
	IF objManDev.SelectedLevelwindIndexHMI = 0 THEN
		objManDev.LevelwindHMI REF= gvlStorageDrum01.spool ;
	ELSE
		objManDev.LevelwindHMI REF= gvlCtd01.spool;
	END_IF
ELSE
	DebugMessage('Reference to Levelwind is missing','','');
END_IF

//gvlMRU.MRU_UDP(
//	DualPositions := TRUE,
//	LocalIPAddr := '10.183.6.170',
//	LocalIPPort := 5678
//	);


]]></ST>
      </Implementation>
    </Method>
    <Method Name="savePersistentData" Id="{8d859ddc-e9a9-4000-b20e-05b2a8c52dd6}">
      <Declaration><![CDATA[METHOD PRIVATE savePersistentData : BOOL
VAR_INST
	//wpd			: WritePersistentData;	
	wpd				:FB_WritePersistentData;	
	state 			: DINT;
END_VAR]]></Declaration>
      <Implementation>
        <ST><![CDATA[wpd(
	NetID 		:= '',
	Port        := 851,
	start 		:= state = 10 OR state = 20,
	tmout		:= DEFAULT_ADS_TIMEOUT,
	mode 		:= E_PersistentMode.SPDM_VAR_BOOST // use more plc cycles if necessary
);

savePersistentData := FALSE;

CASE state OF
	0: 
		state := 10;
		
	10:
		state := 20;
		
	20:
		IF NOT wpd.BUSY OR wpd.ERR THEN
			state := 30;
		END_IF
		
	30:
		savePersistentData := TRUE;
		state := 0;
END_CASE
]]></ST>
      </Implementation>
    </Method>
    <Method Name="updateRadio" Id="{8e398f87-f310-4170-b7b7-2d7d3789294d}">
      <Declaration><![CDATA[METHOD updateRadio : BOOL
VAR_INPUT
END_VAR
]]></Declaration>
      <Implementation>
        <ST><![CDATA[IF NOT config.isConfigured THEN
	RETURN;
END_IF

(*RadioBase CTD David*)
gvlCtdDavid.RadioBase(
	IO_In:= gvlCtdDavid.RadioPanelIO_In, 
	IO_Out:= gvlCtdDavid.RadioPanelIO_Out,
	WinchIO_In := gvlCtd01.RadioDavit_IO_in,
	WinchIO_Out := gvlCtd01.RadioDavit_IO_out,
	WinchControlUnit := gvlCtd01.TriplexDavidRemoteControl		// added to allow radio to stop winch if turned off.
);

gvlCtdDavid.RadioDisplay(
	winch := gvlCtd01.winch,
	loadcell_tension := gvlCtd01.Sheavesensor.Tension,
	useLoadcellTension := TRUE,
	EmergencyStop := objGeneral.estopObject,
	alarm := Obj.alarmCollector,
	HPU := gvlDeckHPU.HPU,
	AFE := ObjPower.IGBT_TA1,
	DeckHydValveActive := gvlCtdDavid.Crane.Active,
	brakeHPU := objBrakeHPU.BrakeHPU1
); 

(*RadioBase Aframe*)
gvlAframe.RadioBase(
	IO_In:= gvlAframe.RadioPanelIO_In, 
	IO_Out:= gvlAframe.RadioPanelIO_Out,
	WinchIO_In := gvlCtd01.RadioAframe_IO_in,
	WinchIO_Out := gvlCtd01.RadioAframe_IO_out,
	WinchControlUnit := gvlCtd01.TriplexAframeRemoteControl		// added to allow radio to stop winch if turned off.
);

gvlAframe.RadioDisplay(
	winch := gvlCtd01.winch,
	loadcell_tension := gvlCtd01.Sheavesensor.Tension,
	useLoadcellTension := TRUE,
	EmergencyStop := objGeneral.estopObject,
	alarm := Obj.alarmCollector,
	HPU := gvlDeckHPU.HPU,
	AFE := ObjPower.IGBT_TA1,
	DeckHydValveActive := gvlAframe.Crane.Active,
	brakeHPU := objBrakeHPU.BrakeHPU1
	
); 

(*RadioBase OHC*)
gvlOHC.RadioBase(
	IO_In:= gvlOHC.RadioPanelIO_In, 
	IO_Out:= gvlOHC.RadioPanelIO_Out,
	WinchIO_In := gvlTractionWinch01.RadioOHC_IO_in,
	WinchIO_Out := gvlTractionWinch01.RadioOHC_IO_out,
	WinchControlUnit := gvlTractionWinch01.TriplexOHCRemoteControl		// added to allow radio to stop winch if turned off.
);

gvlOHC.RadioDisplay(
	winch := gvlStorageDrum01.winch,
	loadcell_tension := gvlTractionWinch01.Sheavesensor.Tension,
	useLoadcellTension := TRUE,
	EmergencyStop := objGeneral.estopObject,
	alarm := Obj.alarmCollector,
	HPU := gvlDeckHPU.HPU,
	AFE := ObjPower.IGBT_TA1,
	TractionWinch := gvlTractionWinch01.winch,
	DeckHydValveActive := gvlOHC.Crane.Active,
	sdrController := gvlStorageDrum01.SDR_controller,
	brakeHPU := objBrakeHPU.BrakeHPU1
	
); ]]></ST>
      </Implementation>
    </Method>
    <Method Name="updateModbus" Id="{9a689777-aebe-4ca6-a4bb-d16eb5b03ca8}">
      <Declaration><![CDATA[METHOD PRIVATE updateModbus : BOOL
VAR
n : INT;
	
END_VAR]]></Declaration>
      <Implementation>
        <ST><![CDATA[// add data to modbus union

ObjModbus.data.input.CTD_SetLength 	:= LREAL_TO_DINT(OpValuesPersistent.opvalues.autoCTD.setpoint * 10);		// 32 bit INT, resolution 10cm 
ObjModbus.data.input.CTD_WireLength := LREAL_TO_DINT(gvlCtd01.winch.Length * 10);								// 32 bit INT, resolution 10cm
ObjModbus.data.input.CTD_WireSpeed 	:= LREAL_TO_INT(gvlCtd01.winch.Velocity * 100);								// 16 bit INT, resolution 0.01 m/s
ObjModbus.data.input.CTD_tension 	:= MAX( 0, LREAL_TO_INT(gvlCtd01.Sheavesensor.Tension  /10));				// 16 bit INT, resolution 10kg

ObjModbus.data.input.ROV_SetLength 	:= LREAL_TO_DINT(OpValuesPersistent.opvalues.autoTraction.setpoint * 10);	// 32 bit INT, resolution 10cm 
ObjModbus.data.input.ROV_WireLength := LREAL_TO_DINT(gvlStorageDrum01.winch.Length * 10);						// 32 bit INT, resolution 10cm
ObjModbus.data.input.ROV_WireSpeed 	:= LREAL_TO_INT(gvlStorageDrum01.winch.Velocity * 100);						// 16 bit INT, resolution 0.01 m/s
ObjModbus.data.input.ROV_tension 	:= MAX( 0, LREAL_TO_INT(gvlTractionWinch01.Sheavesensor.Tension  /10));		// 16 bit INT, resolution 10kg

ObjModbus.data.input.winchmode.CTD_Manual_mode			:= gvlCtd01.winch.Mode = WinchModes.MANUAL;
ObjModbus.data.input.winchmode.CTD_Auto_mode			:= gvlCtd01.winch.Mode = WinchModes.AUTO;
ObjModbus.data.input.winchmode.CTD_General_alarm		:= gvlCtd01.winch.OpState = P6OpState.NOTAVAILABLE;
ObjModbus.data.input.winchmode.ROV_Manual_mode			:= gvlTractionWinch01.winch.Mode = WinchModes.MANUAL;
ObjModbus.data.input.winchmode.ROV_Auto_mode			:= gvlTractionWinch01.winch.Mode = WinchModes.AUTO;
ObjModbus.data.input.winchmode.ROV_General_alarm		:= gvlTractionWinch01.winch.OpState = P6OpState.NOTAVAILABLE;;
	
ObjModbus.data.input.driveAlarm.CTD_Winch_Drive			:= ObjDriveTrain.acs880[EInv.CTD_INV0].OpState = P6OpState.NOTAVAILABLE;
ObjModbus.data.input.driveAlarm.CTD_Spooling_Drive		:= ObjDriveTrain.acs880[EInv.CTD_LEV01_INV0].OpState = P6OpState.NOTAVAILABLE;;
ObjModbus.data.input.driveAlarm.ROV_Traction_drive_1	:= ObjDriveTrain.acs880[EInv.TRACTIONWINCH_INV0].OpState = P6OpState.NOTAVAILABLE;
ObjModbus.data.input.driveAlarm.ROV_Traction_drive_2	:= ObjDriveTrain.acs880[EInv.TRACTIONWINCH_INV1].OpState = P6OpState.NOTAVAILABLE;
ObjModbus.data.input.driveAlarm.ROV_Storage_reel_drive	:= ObjDriveTrain.acs880[EInv.STORAGEDRUM_INV0].OpState = P6OpState.NOTAVAILABLE;
ObjModbus.data.input.driveAlarm.ROV_Spooling_drive    	:= ObjDriveTrain.acs880[EInv.STORAGEDRUM_LEV01_INV0].OpState = P6OpState.NOTAVAILABLE;
ObjModbus.data.input.driveAlarm.Outhauler_drive			:= ObjDriveTrain.acs880[EInv.OUTHAULER_INV0].OpState = P6OpState.NOTAVAILABLE;

ObjModbus.data.input.alarms.Low_oil_level_Servo_pump		:= objBrakeHPU.BrakeHPU1.OilLevelLow;
ObjModbus.data.input.alarms.High_temp_oil_Servo_pump		:= objBrakeHPU.BrakeHPU1.TemperatureHigh;
ObjModbus.data.input.alarms.Low_oil_level_gear_cooling		:= NOT ObjCooling.gearCoolingCtrlIo_in.oilLevel; 		// inverted signal
ObjModbus.data.input.alarms.High_temp_oil_gear_cooling		:= NOT ObjCooling.gearCoolingCtrlIo_in.highOilTemperature; // inverted signal
ObjModbus.data.input.alarms.low_servo_pressure				:= NOT objBrakeHPU.BrakeHPU1.PressureOK AND objBrakeHPU.BrakeHPU1.Active;				
ObjModbus.data.input.alarms.Estop							:= objGeneral.estopObject.Activated;
ObjModbus.data.input.alarms.Deck_machinery_HPU_running		:= gvlDeckHPU.HPU.Pump1_Running OR gvlDeckHPU.HPU.Pump2_Running;
ObjModbus.data.input.alarms.Gear_cooling_HPU_running		:= ObjCooling.gearCoolingController.PumpRunning;
ObjModbus.data.input.alarms.Brake_HPU_running				:= objBrakeHPU.BrakeHPU1.Active;

// Modbus RTU
ObjModbus.slave(
	UnitID 			:= 1,
	AdrInputs 		:= ADR(ObjModbus.data.output),			// read with function code 04 - Address from 0x0000
	SizeInputBytes	:= SIZEOF(ObjModbus.data.output),
	AdrOutputs 		:= ADR(ObjModbus.noData),
	SizeOutputBytes := SIZEOF(ObjModbus.noData),
	AdrMemory		:= ADR(ObjModbus.noData),					// read with function code 03 - read address from 0x4000
	SizeMemoryBytes	:= SIZEOF(ObjModbus.noData),
	ErrorID 		=> ObjModbus.modBusError
	);
	
// copy data to ModbusTCP data arraty for bridge monitor
MEMCPY(ADR(GVL.mb_Input_Registers),ADR(ObjModbus.data.output),40);



]]></ST>
      </Implementation>
    </Method>
    <Method Name="PanelMux" Id="{c6528e85-bffe-421e-a577-d57e0ad920e1}">
      <Declaration><![CDATA[METHOD PanelMux : BOOL
VAR_INPUT
END_VAR
]]></Declaration>
      <Implementation>
        <ST><![CDATA[IF NOT config.isConfigured THEN
	RETURN;
END_IF


ObjManDev.panelMux(
	IWinch			:= ObjDriveTrain.IUserWinches,
	IcontrolUnit	:= ObjManDev.ICtrlUnits
);
(*

objManDev.panelMuxHandling(
	IHandling		:= ObjDriveTrain.IUserHandling,
	IControlUnit	:= ObjManDev.ICtrlUnitsHandling
);
*)]]></ST>
      </Implementation>
    </Method>
    <Method Name="update_TRW" Id="{c9a4fece-9f02-4a7c-97d8-c97f063d0095}">
      <Declaration><![CDATA[METHOD update_TRW : BOOL
VAR_INST
	hasStarted : BOOL;
END_VAR
VAR CONSTANT
	DIM_OUTPUT : p6manualDevices.ConfigDimmableOutputs := (output:= [TRUE, TRUE, TRUE, TRUE]);
END_VAR]]></Declaration>
      <Implementation>
        <ST><![CDATA[IF NOT config.isConfigured THEN
	RETURN;
END_IF

IF NOT hasStarted THEN
	hasStarted := TRUE;
	
	config.drive[EDrv.TRACTION].ID := EDrv.TRACTION; 
	
	gvlTractionWinch01.Drive
		.resetService()
		.attach(ObjDriveTrain.acs880[EInv.TRACTIONWINCH_INV0])
		.attach(ObjDriveTrain.acs880[EInv.TRACTIONWINCH_INV1]);
		
	ObjDriveTrain.IUserWinches[EWinch.TRW] := gvlTractionWinch01.winch;

	ObjManDev.ICtrlUnits[EPanel.TRACTIONWINCH_LOCAL] := gvlTractionWinch01.localCtrlPanel_WP02;
	gvlTractionWinch01.localCtrlPanel_WP02.SetSelectedWinch(gvlTractionWinch01.winch);
	
	ObjManDev.ICtrlUnits[EPanel.TRACTIONWINCH_CTRL_RM] := gvlTractionWinch01.TRWCtrRoomPanell_CP01;
	gvlTractionWinch01.TRWCtrRoomPanell_CP01.SetSelectedWinch(gvlTractionWinch01.winch);
	
	ObjManDev.ICtrlUnits[EPanel.TRACTIONWINCH_HANGAR] := gvlTractionWinch01.hangarCtrlPanel_WP03;
	gvlTractionWinch01.hangarCtrlPanel_WP03.SetSelectedWinch(gvlTractionWinch01.winch);
	
	ObjManDev.ICtrlUnits[EPanel.TRACTIONWINCH_AUTO_AHC] := gvlTractionWinch01.OHCautoControl; 		// will be used to run TRW in CT during launch and recovery
	gvlTractionWinch01.OHCautoControl.SetSelectedWinch(gvlTractionWinch01.winch);
	
	// Triplex radio
	ObjManDev.ICtrlUnits[EPanel.ROV_RADIO_TRIPLEX] := gvlTractionWinch01.TriplexOHCRemoteControl;
	ObjManDev.ICtrlUnits[EPanel.ROV_RADIO_TRIPLEX].SetSelectedWinch(gvlTractionWinch01.winch);
	
	// run first time in the correct sequence
	
	gvlTractionWinch01.Drive(
	Config 		:= config.drive[EDrv.TRACTION], 
	DriveMux 	:= 0
	);
	
		
	ObjDriveTrain.driveInfos[eDrv.TRACTION](Drive:= gvlTractionWinch01.Drive);
	
	gvlTractionWinch01.eWinch(
		Config 				:= config.eWinch[Ewinch.TRW], 
		OpValues 			:= opvalues.ewinch[Ewinch.TRW],
		Drive				:= gvlTractionWinch01.Drive,
		Encoder 			:= ObjDriveTrain.inverters[EInv.TRACTIONWINCH_INV0].getEncoder(0),
		HCController 		:= 0,
		SpoolHeadPosition	:= 0,
		BrakeHPU			:= objBrakeHPU.BrakeHPU1
	);
	
	gvlTractionWinch01.winch(
		WinchID			:= Ewinch.TRW,
		IO_In			:= gvlTractionWinch01.winchIo_in,
		IO_Out			:= gvlTractionWinch01.winchIo_out,
		configUserWinch := config.userWinch[Ewinch.TRW],
		Winch 			:= gvlTractionWinch01.eWinch,
		EmergencyStop 	:= objGeneral.estopObject,
		MotorCooling	:= 0,
		GearCooling		:= objCooling.gearCooling,
		sheaveSensor	:= gvlTractionWinch01.Sheavesensor,
		
		//LoadcellTensionWarningLimit := 12000
	);
	
END_IF


//gvlTractionWinch01.Drive(
//	Config 		:= config.drive[EDrv.TRACTION], 
//	DriveMux 	:= 0
//);

	
//ObjDriveTrain.driveInfos[eDrv.TRACTION](Drive:= gvlTractionWinch01.Drive);

//gvlTractionWinch01.eWinch(
//	Config 				:= config.eWinch[Ewinch.TRW], 
//	OpValues 			:= opvalues.ewinch[Ewinch.TRW],
//	Drive				:= gvlTractionWinch01.Drive,
//	Encoder 			:= ObjDriveTrain.inverters[EInv.TRACTIONWINCH_INV0].getEncoder(0),
//	HCController 		:= 0,
//	SpoolHeadPosition	:= 0,
//	BrakeHPU			:= objBrakeHPU.BrakeHPU1
//);

//gvlTractionWinch01.winch(
//	WinchID			:= Ewinch.TRW,
//	IO_In			:= gvlTractionWinch01.winchIo_in,
//	IO_Out			:= gvlTractionWinch01.winchIo_out,
//	configUserWinch := config.userWinch[Ewinch.TRW],
//	Winch 			:= gvlTractionWinch01.eWinch,
//	EmergencyStop 	:= objGeneral.estopObject,
//	MotorCooling	:= 0,
//	GearCooling		:= objCooling.gearCooling,
//	sheaveSensor	:= gvlTractionWinch01.Sheavesensor,
//	//LoadcellTensionWarningLimit := 12000
//);


gvlTractionWinch01.winch(
	WinchID			:= Ewinch.TRW,
	IO_In			:= gvlTractionWinch01.winchIo_in,
	IO_Out			:= gvlTractionWinch01.winchIo_out,
	configUserWinch := config.userWinch[Ewinch.TRW],
	Winch 			:= gvlTractionWinch01.eWinch,
	EmergencyStop 	:= objGeneral.estopObject,
	MotorCooling	:= 0,
	GearCooling		:= objCooling.gearCooling,
	sheaveSensor	:= gvlTractionWinch01.Sheavesensor,
	DriveConfig		:= config.drive[EDrv.TRACTION],			// used for CT mode
	//LoadcellTensionWarningLimit := 12000
);

gvlTractionWinch01.eWinch(
	Config 				:= config.eWinch[Ewinch.TRW], 
	OpValues 			:= opvalues.ewinch[Ewinch.TRW],
	Drive				:= gvlTractionWinch01.Drive,
	Encoder 			:= ObjDriveTrain.inverters[EInv.TRACTIONWINCH_INV0].getEncoder(0),
	HCController 		:= 0,
	SpoolHeadPosition	:= 0,
	BrakeHPU			:= objBrakeHPU.BrakeHPU1
);

gvlTractionWinch01.Drive(
	Config 		:= config.drive[EDrv.TRACTION], 
	DriveMux 	:= 0
);

ObjDriveTrain.driveInfos[eDrv.TRACTION](Drive:= gvlTractionWinch01.Drive);

(*Panels*)
gvlTractionWinch01.localCtrlPanel_WP02(
	ID					:= EPanel.TRACTIONWINCH_LOCAL,
	IO_In				:= gvlTractionWinch01.deckCtrlPanel_WP02_Io_in,
	IO_Out				:= gvlTractionWinch01.deckCtrlPanel_WP02_Io_out,
	controlUnitMux		:= ObjManDev.panelMux,
	masterControl		:= 0,
	emergencyStop		:= objGeneral.estopObject,
	config				:= config.ctrlBaseUnit[EPanel.TRACTIONWINCH_LOCAL],
	bridgeControl		:= 0,
	winchSelector		:= 0,
	SplitModeController	:= 0,
	manualSpoolControl	:= 0
);	

(*Control Staton 1*)
gvlTractionWinch01.TRWCtrRoomBridgelPanel_CP01(
	DimmableOutputConfig	:= DIM_OUTPUT,
	IO_In					:= gvlTractionWinch01.bridgeCtrlPanel_CP01_Io_in,
	IO_Out					:= gvlTractionWinch01.bridgeCtrlPanel_CP01_Io_out,
	DimCtrl					:= objManDev.dimCtrlRoom,
	BuzzerCtrl				:= objManDev.buzzer
);


gvlTractionWinch01.TRWCtrRoomPanell_CP01.Disable := gvlTractionWinch01.splitModeRequest;
gvlTractionWinch01.TRWCtrRoomPanell_CP01(
	ID 					:= EPanel.TRACTIONWINCH_CTRL_RM,
	IO_In 				:= gvlTractionWinch01.panelTraction_io_in,
	IO_Out 				:= gvlTractionWinch01.panelTraction_io_out,
	controlUnitMux		:= ObjManDev.panelMux,
	masterControl		:= 0,
	emergencyStop		:= objGeneral.estopObject,
	config				:= config.ctrlBaseUnit[EPanel.TRACTIONWINCH_CTRL_RM],
	bridgeControl		:= gvlTractionWinch01.TRWCtrRoomBridgelPanel_CP01,
	manualSpoolControl	:= 0
);

(*Hangar Panel*)
gvlTractionWinch01.hangarCtrlPanel_WP03.Disable := gvlTractionWinch01.splitModeRequest;
gvlTractionWinch01.hangarCtrlPanel_WP03(
	ID					:= EPanel.TRACTIONWINCH_HANGAR,
	IO_In				:= gvlTractionWinch01.hangarCtrlPanel_WP03_IO_In,
	IO_Out				:= gvlTractionWinch01.hangarCtrlPanel_WP03_IO_Out,
	controlUnitMux		:= ObjManDev.panelMux,
	masterControl		:= 0,
	emergencyStop		:= objGeneral.estopObject,
	config				:= config.ctrlBaseUnit[EPanel.TRACTIONWINCH_HANGAR],
	bridgeControl		:= 0,
	winchSelector		:= 0,
	SplitModeController	:= 0,
	manualSpoolControl	:= 0
);

// this is only used for setting  TRW system in CT mode from handling system
gvlTractionWinch01.OHCautoControl.Disable := gvlTractionWinch01.splitModeRequest;
//CT := gvlTractionWinch01.OHCautoControl.IO_Out.manualTorqueIndicator;
gvlTractionWinch01.OHCautoControl(
	ID					:= EPanel.TRACTIONWINCH_AUTO_AHC,
	IO_In				:= gvlTractionWinch01.AHC_auto_io_in, 
	IO_Out				:= gvlTractionWinch01.AHC_auto_io_out, 
	controlUnitMux		:= ObjManDev.panelMux,
	masterControl		:= 0,
	emergencyStop		:= objGeneral.estopObject,
	config				:= config.ctrlBaseUnit[EPanel.TRACTIONWINCH_AUTO_AHC],
	bridgeControl		:= 0,
	winchSelector		:= 0,
	SplitModeController	:= 0,
	manualSpoolControl	:= 0
);	

// radio should be diabled in split mode.
gvlTractionWinch01.TriplexOHCRemoteControl.Disable := gvlTractionWinch01.splitModeRequest;
gvlTractionWinch01.TriplexOHCRemoteControl(
	ID 						:= EPanel.ROV_RADIO_TRIPLEX,
	IO_In					:= gvlTractionWinch01.RadioOHC_IO_in,
	IO_Out					:= gvlTractionWinch01.RadioOHC_IO_out,
	controlUnitMux			:= ObjManDev.panelMux,
	masterControl			:= 0,
	emergencyStop			:= objGeneral.estopObject,
	config					:= config.ctrlBaseUnit[EPanel.CTD_DAVIT_RADIO_TRIPLEX],
	bridgeControl			:= 0,
	manualSpoolControl		:= 0
);

(*Hangar Exor panel*)
objHMI.tractionWinchLength := gvlStorageDrum01.eWinch.Length;
objHMI.tractionWinchTension := gvlTractionWinch01.eWinch.Tension + gvlStorageDrum01.eWinch.Tension;
objHMI.tractionWinchVelocity := gvlStorageDrum01.eWinch.Velocity;

objHMI.winchActiveIndicator := gvlTractionWinch01.hangarCtrlPanel_WP03_IO_Out.winchActiveIndicator;
objHMI.inControlIndicator := gvlTractionWinch01.hangarCtrlPanel_WP03_IO_Out.inControlIndicator;

objHMI.winchAlarmIndicator := gvlTractionWinch01.hangarCtrlPanel_WP03_IO_Out.alarmIndicator;
ObjHMI.blockTension := gvlTractionWinch01.Sheavesensor.Tension;
ObjHMI.blockVelocity := gvlTractionWinch01.Sheavesensor.Length;
// auto

// denne brukes ikke, se instans inni autoController
//	//Lager utgang for posisjon og velocity
	
//	gvlTractionWinch01.trajectoryGenerator(
//		active := gvlTractionWinch01.autoControl.OpState = p6com.P6OpState.RUN,  
//		Setpoint := opvalues.autoTraction.setpoint,					// lengde for winch i meter
//		PV_Length := gvlTractionWinch01.eWinch.Length,				//
//		PV_Velocity := gvlTractionWinch01.eWinch.Velocity,			// m/s
//		PV_Tension := gvlTractionWinch01.eWinch.Tension,			// kg
//		VelocityMax := opvalues.autoTraction.velocityMax,			// m/s
//		TensionMaxKg := opvalues.autoTraction.tensionMaxTon * 1000,	
//		Acceleration := opvalues.autoTraction.accelerationMax,		// m/s*s  how fast should we ramp up and down 
//		AHCActive := opvalues.autoTraction.AHC,						//
//		AHCPositon := gvlMRU.MRU2.AHCPosition,  	// OHC crane // posisjon i meter +- 
//		ErrorMax := 2,												// tallet er i meter , velocity reduseres
//		Scantime := 0.01
//	);
//	// gvlTractionWinch01.trajectoryGenerator.Velocity
//	// Utgang skal brukes til å styre hastighet

gvlTractionWinch01.autoControl(
	Config := config.eWinch[EWinch.TRW],
	OpValues := opvalues.autoTraction,
	Winch := gvlTractionWinch01.winch,
	eWinch := gvlTractionWinch01.eWinch, //
	lengthProcessValue := gvlStorageDrum01.eWinch.Length,
	controlUnit := gvlTractionWinch01.TRWCtrRoomPanell_CP01, // TRWCtrRoomBridgelPanel_CP01,  // has to be change for the right panel
	drive := gvlTractionWinch01.drive,
	AHC := gvlMRU.MRU2,							// OHC crane
	EmergencyStop := objGeneral.estopObject,
	brakeHPU := objBrakeHPU.BrakeHPU1
);

]]></ST>
      </Implementation>
    </Method>
    <Method Name="updateOHC" Id="{d1f41c74-0c2e-4a7d-a781-befd359323b6}">
      <Declaration><![CDATA[METHOD updateOHC : BOOL	// OverHeadCrane
(*no control unit mux... make a local one by having crane controller point to a panel interface, then have one off these panels point to that interface*)]]></Declaration>
      <Implementation>
        <ST><![CDATA[IF NOT config.isConfigured THEN
	RETURN;
END_IF

IF EnteredRun.Q THEN//prepopulate
	ObjManDev.OHCPanel := gvlOHC.Radio_Panel;
END_IF


(*Deck Panel*)
gvlOHC.Deck_Panel(
	_id:= HPanel.Deck_OHC, 
	emergencyStop:= objGeneral.estopObject, 
	Equipment:= gvlOHC.Crane,
	Config:= Config.DeckPanelOHC, 
	IO_In:= gvlOHC.Deck_PanelIO_In, 
	IO_Out:= gvlOHC.Deck_PanelIO_Out
);
	
(*Radio Panel*)
gvlOHC.Radio_Panel(
	_id:= HPanel.Radio_Aframe, 
	Config:= Config.RadioPanelOHC, 
	IO_In:= gvlOHC.Radio_PanelIO_In, 
	IO_Out:= gvlOHC.Radio_PanelIO_Out, 
	emergencyStop:= objGeneral.estopObject, 
	Equipment:= gvlOHC.Crane,
	HBCIO_Out:= gvlOHC.RadioPanelIO_Out, 
	HBCIO_In:= gvlOHC.RadioPanelIO_In, 
	RadioBase:= gvlOHC.RadioBase
);

(*Panel selection*)
IF gvlOHC.Deck_Panel.EventActivateButton AND NOT gvlOHC.Radio_Panel.InControl THEN
	ObjManDev.OHCPanel := gvlOHC.Deck_Panel;
ELSIF gvlOHC.Radio_Panel.EventActivateButton AND NOT gvlOHC.Deck_Panel.InControl THEN
	ObjManDev.OHCPanel := gvlOHC.Radio_Panel;
END_IF

(*Crane Controller*)
gvlOHC.Crane(
	_id:= HDrv.OverHeadCrane, 
	emergencyStop:= objGeneral.estopObject, 
	Config:= config.CtrlOHC, 
	Panel := ObjManDev.OHCPanel, //gvlOHC.Radio_Panel,
	IO_In:= gvlOHC.HandlingIo_in, 
	IO_Out:= gvlOHC.HandlingIo_Out,
	winch := gvlTractionWinch01.winch		// to check for opstate and CT in LAR
);

(*Calibrating finished*)
IF gvlOHC.Crane.SavePdata THEN
	startSavePData := TRUE;
END_IF

]]></ST>
      </Implementation>
    </Method>
    <Method Name="updateAHC" Id="{dd6ef1c9-61b5-4581-9c8f-725a648d02cf}">
      <Declaration><![CDATA[METHOD updateAHC : BOOL
VAR_INPUT
END_VAR
]]></Declaration>
      <Implementation>
        <ST><![CDATA[]]></ST>
      </Implementation>
    </Method>
    <Method Name="update_CTD" Id="{e793b208-a7e1-4675-819a-2d682354eaf3}">
      <Declaration><![CDATA[METHOD update_CTD : BOOL
VAR_INST
	hasStarted : BOOL;
	//setOffset : BOOL;
END_VAR
VAR CONSTANT
	DIM_OUTPUT : p6manualDevices.ConfigDimmableOutputs := (output:= [TRUE, TRUE, TRUE, TRUE]);
END_VAR
]]></Declaration>
      <Implementation>
        <ST><![CDATA[IF NOT config.isConfigured THEN
	RETURN;
END_IF

IF NOT hasStarted THEN
	hasStarted := TRUE;
	
	config.drive[EDrv.CTD].ID := EDrv.CTD;
	
	gvlCtd01.drive
		.resetService()
		.attach(ObjDriveTrain.acs880[EInv.CTD_INV0]);
		
	gvlCtd01.spool_drive	//Spool have no Mux
		.resetService()
		.attach(ObjDriveTrain.acs880[EInv.CTD_LEV01_INV0]);	//Inv for spool

	ObjDriveTrain.IUserWinches[eWinch.CTD] := gvlCtd01.winch; 
	// assign spool object to HMI array
	ObjDriveTrain.arrayISpool[espool.CTD01] := gvlCtd01.spool;
	
	ObjManDev.ICtrlUnits[EPanel.CTD_DECK_PANEL] := gvlCtd01.winchRoomCtrlPanel_WP01;
	gvlCtd01.winchRoomCtrlPanel_WP01.SetSelectedWinch(gvlCtd01.winch);
	
	ObjManDev.ICtrlUnits[EPanel.CTD_AFT_CTRL] := gvlCtd01.aftCtrlRmPanel_CP03;
	gvlCtd01.aftCtrlRmPanel_CP03.SetSelectedWinch(gvlCtd01.winch);
	
	ObjManDev.ICtrlUnits[EPanel.CTD_DAVIT_RADIO_TRIPLEX] := gvlCtd01.TriplexDavidRemoteControl;
	gvlCtd01.TriplexDavidRemoteControl.SetSelectedWinch(gvlCtd01.winch);
		
	ObjManDev.ICtrlUnits[EPanel.CTD_AFRAME_RADIO_TRIPLEX] := gvlCtd01.TriplexAframeRemoteControl;
	gvlCtd01.TriplexAframeRemoteControl.SetSelectedWinch(gvlCtd01.winch);
	
	
END_IF

gvlCtd01.drive(		//winch
	Config 		:= config.drive[EDrv.CTD], 
	DriveMux 	:= 0
); 
ObjDriveTrain.driveInfos[eDrv.CTD](Drive:= gvlCtd01.drive);

gvlCtd01.spool_drive(	//spool
	Config 		:= config.drive[EDrv.SPOOL_CTD], 
	DriveMux 	:= 0,
);	
ObjDriveTrain.driveInfos[EDrv.SPOOL_CTD](Drive:= gvlCtd01.spool_drive);

gvlCtd01.eWinch(
	Config 				:= config.EWinch[EWinch.CTD],
	OpValues 			:= opvalues.ewinch[EWinch.CTD],
	Drive 				:= gvlCtd01.drive,
	Encoder		 		:= ObjDriveTrain.inverters[EInv.CTD_INV0].getEncoder(0),
	HCController 		:= 0,
	SpoolHeadPosition	:= gvlCtd01.spool.HeadPosition,
	BrakeHPU			:= objBrakeHPU.BrakeHPU1
);

gvlCtd01.spool(
	ID					:= ESpool.CTD01,
	Config 				:= Config.spool[ESpool.CTD01],
	IO_In 				:= gvlCtd01.spool_io_in,
	WinchConfig			:= Config.eWinch[EWinch.CTD],
	OpValues 			:= OpValuesPersistent.opvalues.ctd_spool,
	Winch 				:= gvlCtd01.eWinch, //Winch,
	Drive 				:= gvlCtd01.spool_drive,
	Encoder 			:= ObjDriveTrain.inverters[EInv.CTD_LEV01_INV0].getEncoder(0), 
	//EncoderWinch 		:= 0,
	FollowUpSensor 		:= IOin.sensorFollowUpCtd,
	EmergencyStop		:= objGeneral.estopObject,
);	

gvlCtd01.winch.BlockStopSignal := gvlCtdDavid.Crane.FullyCompressed;
gvlCtd01.winch.ReduceConstantTorqueSignal := gvlCtdDavid.Crane.HalfCompressed;

gvlCtd01.winch(
	WinchID			:= Ewinch.CTD,
	IO_In			:= gvlCtd01.winchIo_in,
	IO_Out			:= gvlCtd01.winchIo_out,
	configUserWinch := config.userWinch[Ewinch.CTD],
	Winch 			:= gvlCtd01.eWinch,
	EmergencyStop 	:= objGeneral.estopObject,
	MotorCooling	:= 0,
	GearCooling		:= 0,
	sheaveSensor	:= gvlCtd01.Sheavesensor,
	//LoadcellTensionWarningLimit := 1000
);

(*Panels*)
gvlCtd01.winchRoomCtrlPanel_WP01(
	ID					:= EPanel.CTD_DECK_PANEL,
	IO_In				:= gvlCtd01.deckCtrlPanel_WP01_Io_in,
	IO_Out				:= gvlCtd01.deckCtrlPanel_WP01_Io_out,
	controlUnitMux		:= ObjManDev.panelMux,
	masterControl		:= 0,
	emergencyStop		:= objGeneral.estopObject,
	config				:= config.ctrlBaseUnit[EPanel.CTD_DECK_PANEL],
	bridgeControl		:= 0,
	winchSelector		:= 0,
	SplitModeController	:= 0,
	manualSpoolControl	:= gvlCtd01.manSpool_deckCtrl_WP01
);

(*Spool*)
gvlCtd01.manSpool_deckCtrl_WP01(	
	IO_In 	:= gvlCtd01.deckCtrlPanel_WP01_manSpoolIO_In,
	spool 	:= gvlCtd01.spool
);	

(*Control Station CP02*)
gvlCtd01.bridge_AftCtrlRmPanel_CP03(
	DimmableOutputConfig	:= DIM_OUTPUT,
	IO_In					:= gvlCtd01.bridgeCtrlPanel_CP02_Io_in,
	IO_Out					:= gvlCtd01.bridgeCtrlPanel_CP02_Io_out,
	DimCtrl					:= objManDev.dimCtrlAftStation,
	BuzzerCtrl				:= objManDev.buzzer
);

gvlCtd01.aftCtrlRmPanel_CP03(
	ID 						:= EPanel.CTD_AFT_CTRL,
	IO_In					:= gvlCtd01.panelCTD_io_in,
	IO_Out					:= gvlCtd01.panelCTD_io_out,
	controlUnitMux			:= ObjManDev.panelMux,
	masterControl			:= 0,
	emergencyStop			:= objGeneral.estopObject,
	config					:= config.ctrlBaseUnit[EPanel.CTD_AFT_CTRL],
	bridgeControl			:= gvlCtd01.bridge_AftCtrlRmPanel_CP03,
	manualSpoolControl		:= 0
);

gvlCtd01.TriplexDavidRemoteControl(
	ID 						:= EPanel.CTD_DAVIT_RADIO_TRIPLEX,
	IO_In					:= gvlCtd01.RadioDavit_IO_in,
	IO_Out					:= gvlCtd01.RadioDavit_IO_out,
	controlUnitMux			:= ObjManDev.panelMux,
	masterControl			:= 0,
	emergencyStop			:= objGeneral.estopObject,
	config					:= config.ctrlBaseUnit[EPanel.CTD_DAVIT_RADIO_TRIPLEX],
	bridgeControl			:= 0,
	manualSpoolControl		:= 0
);

gvlCtd01.TriplexAframeRemoteControl(
	ID 						:= EPanel.CTD_AFRAME_RADIO_TRIPLEX,
	IO_In					:= gvlCtd01.RadioAframe_IO_in,
	IO_Out					:= gvlCtd01.RadioAframe_IO_out,
	controlUnitMux			:= ObjManDev.panelMux,
	masterControl			:= 0,
	emergencyStop			:= objGeneral.estopObject,
	config					:= config.ctrlBaseUnit[EPanel.CTD_AFRAME_RADIO_TRIPLEX],
	bridgeControl			:= 0,
	manualSpoolControl		:= 0
);


gvlCtd01.autoControl(
	Config := config.eWinch[EWinch.CTD],
	OpValues := opvalues.autoCTD,
	Winch := gvlCtd01.winch,
	eWinch := gvlCtd01.eWinch,
	lengthProcessValue := gvlCtd01.eWinch.Length,
	controlUnit := gvlCtd01.aftCtrlRmPanel_CP03,  // has to be change for the right panel
	drive := gvlCtd01.drive,
	AHC := gvlMRU.MRU1,							// Select one of the two inputs (1: A-frame 2: CTD)
	EmergencyStop := objGeneral.estopObject,
	brakeHPU := objBrakeHPU.BrakeHPU1
);

]]></ST>
      </Implementation>
    </Method>
    <Method Name="updateKN75" Id="{f6e2e9e9-d763-465a-9c6d-86f146a74fcf}">
      <Declaration><![CDATA[METHOD updateKN75 : BOOL
VAR_INPUT
END_VAR
(*This crane have no panels within the PLC...*)]]></Declaration>
      <Implementation>
        <ST><![CDATA[IF NOT config.isConfigured THEN
	RETURN;
END_IF


gvlKN75.Crane(
	_id:= HDrv.KN75, 
	emergencyStop:= objGeneral.estopObject, 
	Config:= config.CtrlKN75, 
	IO_In:= gvlKN75.HandlingIo_in, 
	IO_Out:= gvlKN75.HandlingIo_Out
);



]]></ST>
      </Implementation>
    </Method>
    <Method Name="updateCtdDavid" Id="{fb0e8b6b-491a-4f2c-b658-1c968f827235}">
      <Declaration><![CDATA[METHOD updateCtdDavid : BOOL
(*no control unit mux... make a local one by having crane controller point to a panel interface, then have one off these panels point to that interface*)]]></Declaration>
      <Implementation>
        <ST><![CDATA[IF NOT config.isConfigured THEN
	RETURN;
END_IF
IF EnteredRun.Q THEN//prepopulate
	ObjManDev.CtdDavidPanel := gvlCtdDavid.Radio_Panel;
END_IF
	
(*Deck Panel*)
gvlCtdDavid.Deck_Panel(
	_id:= HPanel.Deck_CtdDavid, 
	emergencyStop:= objGeneral.estopObject, 
	Equipment:= gvlCtdDavid.Crane,
	Config:= Config.DeckPanelCtdDavid, 
	IO_In:= gvlCtdDavid.Deck_PanelIO_In, 
	IO_Out:= gvlCtdDavid.Deck_PanelIO_Out
);

(*Radio Panel*)
gvlCtdDavid.Radio_Panel(
	_id:= HPanel.Radio_CtdDavid, 
	Config:= Config.RadioPanelCtdDavid, 
	IO_In:= gvlCtdDavid.Radio_PanelIO_In, 
	IO_Out:= gvlCtdDavid.Radio_PanelIO_Out, 
	emergencyStop:= objGeneral.estopObject, 
	Equipment:= gvlCtdDavid.Crane,
	HBCIO_Out:= gvlCtdDavid.RadioPanelIO_Out, 
	HBCIO_In:= gvlCtdDavid.RadioPanelIO_In, 
	RadioBase:= gvlCtdDavid.RadioBase
);

(*Panel selection*)
IF gvlCtdDavid.Deck_Panel.EventActivateButton AND NOT gvlCtdDavid.Radio_Panel.InControl THEN
	ObjManDev.CtdDavidPanel := gvlCtdDavid.Deck_Panel;
ELSIF gvlCtdDavid.Radio_Panel.EventActivateButton AND NOT gvlCtdDavid.Deck_Panel.InControl THEN
	ObjManDev.CtdDavidPanel := gvlCtdDavid.Radio_Panel;
END_IF

(*Crane Controller*)
gvlCtdDavid.Crane(
	_id:= HDrv.CtdDavid, 
	emergencyStop:= objGeneral.estopObject, 
	Config:= config.CtrlCtdDavid, 
	Panel := ObjManDev.CtdDavidPanel,//gvlCtdDavid.Radio_Panel,
	IO_In:= gvlCtdDavid.HandlingIo_in, 
	IO_Out:= gvlCtdDavid.HandlingIo_Out
);




]]></ST>
      </Implementation>
    </Method>
  </POU>
</TcPlcObject>