﻿<?xml version="1.0" encoding="utf-8"?>
<TcPlcObject Version="1.1.0.1">
  <POU Name="HBC_DisplayHandler" Id="{78aa8279-61aa-0d6e-20cc-e86947c08e05}" SpecialFunc="None">
    <Declaration><![CDATA[// FB to produce and send all output to a standard HBC Spectrum D radio screen.
FUNCTION_BLOCK HBC_DisplayHandler
VAR_INPUT
//	IO_In 				: POINTER TO p6manualdevices.RCU_HBC_IO_In;		// data from Radio - Currently not in use....
//	IO_Out				: REFERENCE TO p6manualdevices.RCU_HBC_IO_Out; 	// data to Radio : 6200(1-8), 6200(9-0x10), 6200(0x11-0x18), 6200(0x19-0x20),
	winch 				: p7type.IBaseUserWinch;						// for length, speed, tension and modes
	loadcell_tension	: LREAL; // if used 
	useLoadcellTension 	: BOOL;
	EmergencyStop		: p6com.IEmergencyStop;
	alarm 				: REFERENCE TO p6com.AlarmCollector;
	HPU 				: REFERENCE TO DeckHPU;
	AFE					: REFERENCE TO p6power.ACS880IGBT;
	TractionWinch		: p7type.IBaseUserWinch;
	DeckHydValveActive	: BOOL;
	sdrController		: REFERENCE TO  SDR_Controller;
	brakeHPU			: REFERENCE TO localHPUBrake;
	
END_VAR
VAR_OUTPUT
END_VAR

VAR
	// remember to add IO in/out when instanciating object
	// DisplayHandler := (IO_In := ADR(gvlOHC.RadioPanelIO_In) , IO_Out := gvlOHC.RadioPanelIO_Out)
	//_In 		: POINTER TO RCU_HBC_IO_In;	// data from Radio
	//_Out		: REFERENCE TO RCU_HBC_IO_Out; 	// data to Radio : 6200(1-8), 6200(9-0x10), 6200(0x11-0x18), 6200(0x19-0x20),
	// initiated in fb_init:
	IO_In 				: REFERENCE TO p6manualdevices.RCU_HBC_IO_In;		// data from Radio - Currently not in use....
	IO_Out				: REFERENCE TO p6manualdevices.RCU_HBC_IO_Out; 	// data to Radio : 6200(1-8), 6200(9-0x10), 6200(0x11-0x18), 6200(0x19-0x20),
	
	SdrOpStatus			:	P6OpState ;
		
	pLength		: p_4Bytes;
	pTension	: p_2Bytes;
	pSpeed   	: p_2Bytes;
	_firstRun	: BOOL := TRUE;
	length		: DINT := 65432;
	tension		: UINT := 2345;
	speed		: UINT := 3456;
	
	alarm_estop : INT;	// to sum up binary signals for alarm
	dummy : INT;
	line2 : INT ;
	line3 : INT;
	line4 : INT;
	winchIndications	: p7type.IBaseUserWinch; // used to select the correct winch to show CT, Manual tension etc.
END_VAR
]]></Declaration>
    <Implementation>
      <ST><![CDATA[// Note: dereference since it's a pointer
// https://infosys.beckhoff.com/english.php?content=../content/1033/tc3_plc_intro/2529458827.html&id=
// test := IO_In^.txpdo0[3] ;

IF  NOT (__ISVALIDREF(IO_In) AND __ISVALIDREF(IO_out)) THEN
	RETURN;
END_IF

IF __ISVALIDREF(sdrController) THEN
	SdrOpStatus := sdrController.opState;
END_IF

IF _firstRun THEN
	_firstRun := FALSE;
	// Copy pointers into Union
	pLength.bytes 	:= ADR(IO_Out.rxpdo0[0]);
	pTension.bytes 	:= ADR(IO_Out.rxpdo0[4]);
	pSpeed.bytes 	:= ADR(IO_Out.rxpdo0[6]);
	
	// if reference to traction winch is included, use this for indications on radio. Winch will be used for lengths, speed etc.
	IF TractionWinch <> 0 THEN
		winchIndications := TractionWinch;
	ELSE
		winchIndications := winch;
	END_IF
END_IF

IF _keepAlive() THEN		// only run on tick from keepalive 
			
	pLength.value^ 	:= 	FLOAT_TO_DINT(winch.Length * 10) ;					// show with one desimal
	tension 		:= 	FLOAT_TO_UINT(SEL(useLoadcellTension, ABS(winch.Tension), loadcell_tension) / 10);	// pick one
	pTension.value^ := 	tension ; 										// show as ton with two desimals
	pSpeed.value^ 	:=	FLOAT_TO_UINT(ABS(winch.Velocity) * 60);			// show as m/min...
	dummy:= 	FLOAT_TO_INT( loadcell_tension);
	
	
	//  **********   HBC LINE 4 HPU AND VALVE******************
	IF HPU.OpState = p7type.P6OpState.RUN THEN
		IF DeckHydValveActive THEN
				line4 := 20; // text: HPU RUN VALVE ACTIVE from message_line4.txt 
		ELSE	// running, but no valve open
			line4 := 21; // text: HPU RUN VALVE CLOSED from message_line4.txt 
		END_IF
		//line4 := 17; // text: HPU RUN from message_line4.txt 
	ELSE
		line4 := 18; // text: HPU STOP from message_line4.txt 
	END_IF
	
	IF HPU.OpState = P6OpState.NOTAVAILABLE THEN
		line4 := 19; // text: HPU ERROR from message_line4.txt 
	END_IF
	
//	NOTAVAILABLE	:= -1,
//	STOPPED			:= 0,
//	PAUSING			:= 1,
//	PREPARE			:= 2,
//	RUN  			:= 3
	
	
//  **********   HBC LINE 2 WINCH INDICATIONS ******************
	dummy := winchIndications.OpState;
	CASE winchIndications.OpState OF
		p7type.P6OpState.RUN:
			line2 := 2; // RUN
		p7type.P6OpState.STOPPED:
			line2 := 1; // stop
	ELSE
		line2 := 6; //  '-' (dash)
	END_CASE
	
	IF  TractionWinch <> 0 THEN
		IF TractionWinch.ManMode = WinchManualModes.MANUAL_TORQUE THEN
			line2 := 3; //  Manual torque
		END_IF
	END_IF
	// for CTD winch
	IF winch.ManMode = WinchManualModes.MANUAL_TORQUE THEN
		line2 := 3; //  Manual torque
	END_IF
	
	IF SdrOpStatus = P6OpState.PREPARE THEN 
		line2 := 13; //  SWC STARTING....	
	END_IF
	IF SdrOpStatus = P6OpState.PAUSING THEN 
		line2 := 14; //  SWC parking....	
	END_IF

//	CASE winchIndications.ManMode OF
//		p7type.WinchManualModes.NORMAL:
//			line2 := 2; // RUN
//		p7type.WinchManualModes.MANUAL_TORQUE:
//			line2 := 3; // man torque
//		p7type.WinchManualModes.CONSTANT_TORQUE:
//			line2 := 4; // CONST TORQUE
//	END_CASE
//	// overwrites the previous if necessary
//	CASE winchIndications.Mode OF
//		p7type.WinchModes.IDLE:
//			line2 := 1; 		// STOP
//		p7type.WinchModes.SLAVE:
//			line2 := 5; 		// AUTO
//		p7type.WinchModes.AUTO:	// maybe this instead?
//			line2 := 5; 		// AUTO
//		p7type.WinchModes.MANUAL:	// 
//			line2 := 2; 		// RUN
//		p7type.WinchModes.TORQUE:	// 
//			line2 := 4; 		// CT
//	END_CASE

//  **********   HBC LINE 3 DC and HPU status ******************
	line3 := 0;
	CASE AFE.OpState OF
		p7type.P6OpState.RUN:
			line3 := 16; 		// DC OK
		p7type.P6OpState.STOPPED:
			line3 := 17; 		// DC OFF
		p7type.P6OpState.NOTAVAILABLE:
			line3 := 18; 		// DC Error
	END_CASE
	
	IF line3 > 15 AND line3 < 19 THEN
		IF brakeHPU.PressureOK THEN
			line3 := line3 + 3;
		ELSE
			line3 := line3 + 6;
		END_IF
	END_IF
	IF AFE.OpState = P6OpState.PREPARE THEN
		line3 := 17;
	END_IF
	
	//
	//
	//
	
// copy line numbers to PDO
	
	IO_Out.rxpdo1[0] := 1;						// message  1 winch name
	IO_Out.rxpdo1[1] := INT_TO_BYTE(line2);		// message  2 winch state
	IO_Out.rxpdo1[2] := INT_TO_BYTE(line3);		// message  3 INFO 1
	IO_Out.rxpdo1[3] := INT_TO_BYTE(line4);		// message  4  INFO 2
	
	// add alarm and estop bits to correct bit location
	alarm_estop :=  SHL(BOOL_TO_INT(alarm.AlarmWarning) , 4); 					// bitl 5/6
	alarm_estop :=  alarm_estop  + SHL(BOOL_TO_INT(alarm.AlarmCritical) , 4);	// bitl 5/6 
	//alarm_estop :=  alarm_estop  + SHL(BOOL_TO_INT(alarm.AlarmCritical) , 5);	// bitl 5/6 Need both bits on
	alarm_estop :=  alarm_estop  + SHL(BOOL_TO_INT(EmergencyStop.Activated) , 6);		//bit 6/7
	
	//dummy := SEL(winch.ManMode = WinchManualModes.CONSTANT_TORQUE,0,1);
{warning disable C0139} // Code with no effect
	winch.ManMode;
	winch.Mode;
	winchIndications.ManMode;
	winchIndications.Mode ;
	
	// lines to show
	IO_Out.rxpdo2[0] := INT_TO_BYTE( e_line1_4.LINE1 + e_line1_4.LINE2 + e_line1_4.LINE3 + e_line1_4.LINE4) ;		// line 1 +2 + winch display
	IO_Out.rxpdo2[1] := INT_TO_BYTE( e_line5_8.LINE5 +  e_line5_8.LINE6 + alarm_estop) ;		// line line 5 + 6  alarm and estop
	IO_Out.rxpdo2[2] :=  SEL(winchIndications.Mode = WinchModes.TORQUE,0,1);		// show line 8 (bottom Green *TensionControlActivated")  
	
	
	// add up desimal points
	IO_Out.rxpdo2[4] := INT_TO_BYTE( e_DP.L_0 + e_DP.S_ + e_DP.T_00);	// length 1 decimal, tension 2 desimals
END_IF
]]></ST>
    </Implementation>
    <Method Name="FB_init" Id="{064d115b-c484-05b1-193c-d3f8e20fcbe3}">
      <Declaration><![CDATA[METHOD FB_init : BOOL
VAR_INPUT
	bInitRetains : BOOL; // if TRUE, the retain variables are initialized (warm start / cold start)
	bInCopyCode : BOOL;  // if TRUE, the instance afterwards gets moved into the copy code (online change)
	IO_In_ref : REFERENCE TO p6manualdevices.RCU_HBC_IO_In;
	IO_Out_ref : REFERENCE TO p6manualdevices.RCU_HBC_IO_Out; 
END_VAR
]]></Declaration>
      <Implementation>
        <ST><![CDATA[THIS^.IO_In REF= IO_In_ref;
THIS^.IO_Out REF= IO_Out_ref;]]></ST>
      </Implementation>
    </Method>
    <Method Name="_keepAlive" Id="{72b1785f-786e-0d03-2611-48e1410fb1e3}">
      <Declaration><![CDATA[// will toggle some unused data every second just to keep display active
METHOD PRIVATE _keepAlive : BOOL
VAR_INPUT
END_VAR
VAR_INST
	KeepAlive	: ton := (PT := T#500MS)   ;
	keepAliveToggle : toggle;
END_VAR]]></Declaration>
      <Implementation>
        <ST><![CDATA[Keepalive(IN := NOT keepalive.Q);
keepAliveToggle( ToggleInput := KeepAlive.Q);
IO_Out.rxpdo1[7] := BOOL_TO_BYTE(keepAliveToggle.value) ;		// rxpdo1[7] is unused
IF keepalive.Q THEN
	_keepAlive := true;
END_IF]]></ST>
      </Implementation>
    </Method>
  </POU>
</TcPlcObject>