
(* @NESTEDCOMMENTS := 'Yes' *)
(* @PATH := '' *)
(* @OBJECTFLAGS := '0, 8' *)
(* @SYMFILEFLAGS := '2048' *)
FUNCTION_BLOCK myModbusKoppler_2
(* Special function block to handle following node
	750-841: Ethernet-Controller   
	750-504: 4DO(DC24V/0.5A) 
	750-504: 4DO(DC24V/0.5A)
	750-504: 4DO(DC24V/0.5A)
	750-504: 4DO(DC24V/0.5A)
	750-504: 4DO(DC24V/0.5A)
	750-402: 4DI(DC24V/3ms)  
	750-402: 4DI(DC24V/3ms)  
	750-402: 4DI(DC24V/3ms)  
	750-404: Counter Device
	750-461: 2AI (PT100) 
	750-600: BusTerminal
*)
VAR_INPUT
	(* Config *)
	xEnable : BOOL;
	sIpAddress : STRING; (* IP-Address of Ethernet-Coupler *)
	tInterval : TIME := t#1s; (* Send Modbus request every x seconds *)
	(* Remote outputs *)
	x504_M1_C1 : BOOL; (* First 504 Channel 1 *)
	x504_M1_C2 : BOOL; (* First 504 Channel 2 *)
	x504_M1_C3 : BOOL; (* First 504 Channel 3 *)
	x504_M1_C4 : BOOL; (* First 504 Channel 4 *)
	x504_M2_C1 : BOOL; (* 504 Channel 1*)
	x504_M2_C2 : BOOL; (* 504 Channel 2*)
	x504_M2_C3 : BOOL; (* 504 Channel 3*)
	x504_M2_C4 : BOOL; (* 504 Channel 4*)
	x504_M3_C1 : BOOL; (* 504 Channel 1*)
	x504_M3_C2 : BOOL; (* 504 Channel 2*)
	x504_M3_C3 : BOOL; (* 504 Channel 3*)
	x504_M3_C4 : BOOL; (* 504 Channel 4*)
	x504_M4_C1 : BOOL; (* 504 Channel 1*)
	x504_M4_C2 : BOOL; (* 504 Channel 2*)
	x504_M4_C3 : BOOL; (* 504 Channel 3*)
	x504_M4_C4 : BOOL; (* 504 Channel 4*)
	x504_M5_C1 : BOOL; (* 504 Channel 1*)
	x504_M5_C2 : BOOL; (* 504 Channel 2*)
	x504_M5_C3 : BOOL; (* 504 Channel 3*)
	x504_M5_C4 : BOOL; (* 504 Channel 4*)
	x404_M9i_C1 : BOOL; (* 404 Channel 1*)
	x404_M9i_C2 : BOOL; (* 404 Channel 2*)
END_VAR
VAR_OUTPUT
	(* Status*)
	xValidValues : BOOL; (* Indicates that every thing is working well *)
	(* Remote inputs *)
	x402_M6_C1 : BOOL; (* Modul 6 _ 402 Channel 1*)
	x402_M6_C2 : BOOL; (* Channel 2*)
	x402_M6_C3 : BOOL; (* Channel 3*)
	x402_M6_C4 : BOOL; (* Channel 4*)
	x402_M7_C1 : BOOL; (* Channel 1*)
	x402_M7_C2 : BOOL; (* Channel 2*)
	x402_M7_C3 : BOOL; (* Channel 3*)
	x402_M7_C4 : BOOL; (* Channel 4*)
	x402_M8_C1 : BOOL; (* Channel 1*)
	x402_M8_C2 : BOOL; (* Channel 2*)
	x402_M8_C3 : BOOL; (* Channel 3*)
	x402_M8_C4 : BOOL; (* Channel 4*)
	x404_M9_C1 : BOOL; (* U/D    Channel 1 *)
	x404_M9_C2 : BOOL; (* Cont. Channel 2 *)
	r461_M10_C1 : REAL; (* 461 Channel 1 *)
	r461_M10_C2 : REAL; (* 461 Channel 2 *)
END_VAR
VAR
	wState : WORD; (* The statemachine *)

	(* Local Modbus-Master-FB *)
	oMbMaster : ETHERNET_MODBUSMASTER_UDP;
	abRxBuffer : ARRAY [0..250] OF BYTE; (* Set Buffersize to maximum payload of any Modbus-Telegram, to be save for future extension*)
	abTxBuffer : ARRAY [0..250] OF BYTE;
	xConnect : BOOL;
	xSend : BOOL;

	oTon : TON; (* Timer for periodic send of Modbus request *)

	(* Helpers *)
	wHelp : WORD;
	pabHelp : POINTER TO ARRAY[0..2] OF BYTE;
END_VAR
(* @END_DECLARATION := '0' *)
(* Call FB every plc cycle *)
oMbMaster(	xOPEN_SOCKET:= xConnect,
			strIP_ADDRESS:= sIpAddress,
			wPORT:= 502,
			bFUNCTION_CODE:= 23,     (*FC23: READ/WRITE-MULTIPLE-REGISTER *)
			wREAD_ADDRESS:= 0,
			wREAD_QUANTITY:= 10,     (* Read first 10 WORD's of input process image - should be enough for the moment *)
			ptREAD_DATA:= ADR(abRxBuffer),
			wWRITE_ADDRESS:= 0,
			wWRITE_QUANTITY:= 10,
			ptSEND_DATA:= ADR(abTxBuffer),
			tTIME_OUT:= (tInterval/2),
			xSEND:= xSend);

CASE wState OF

0: (* IDLE - Wait for something to do *)
	IF xEnable THEN
		oTon(IN:=TRUE, PT:=tInterval);
		IF oTon.Q THEN
			oTon(IN:=FALSE);

			wState := 10;
		END_IF
	ELSE
		xValidValues := FALSE;
		oTon(IN:=FALSE);
	END_IF

10: (* Map data to write into transmit buffer *)
	(* Format analog output data for 750-550: 0==16#0000==0V; 32767==16#7FFF==10V *)
(*	pabHelp := ADR(wHelp);
	(* Channel 1 *)
	wHelp := REAL_TO_WORD(r550_M1_C1/10.0 * 32767);
	abTxBuffer[0] := pabHelp^[0];
	abTxBuffer[1] := pabHelp^[1];
	(* Channel 2 *)
	wHelp := REAL_TO_WORD(r550_M1_C2/10.0 * 32767);
	abTxBuffer[2] := pabHelp^[0];
	abTxBuffer[3] := pabHelp^[1];  *)

	(* Assign digital outputs *)
	abTxBuffer[4].0 := x504_M1_C1;
	abTxBuffer[4].1 := x504_M1_C2;
	abTxBuffer[4].2 := x504_M1_C3;
	abTxBuffer[4].3 := x504_M1_C4;
	abTxBuffer[4].4 := x504_M2_C1;
	abTxBuffer[4].5 := x504_M2_C2;
	abTxBuffer[4].6 := x504_M2_C3;
	abTxBuffer[4].7 := x504_M2_C4;
	abTxBuffer[5].0 := x504_M3_C1;
	abTxBuffer[5].1 := x504_M3_C2;
	abTxBuffer[5].2 := x504_M3_C3;
	abTxBuffer[5].3 := x504_M3_C4;
	abTxBuffer[5].4 := x504_M4_C1;
	abTxBuffer[5].5 := x504_M4_C2;
	abTxBuffer[5].6 := x504_M4_C3;
	abTxBuffer[5].7 := x504_M4_C4;
	abTxBuffer[6].0 := x504_M5_C1;
	abTxBuffer[6].1 := x504_M5_C2;
	abTxBuffer[6].2 := x504_M5_C3;
	abTxBuffer[6].3 := x504_M5_C4;
	abTxBuffer[6].4 := x404_M9i_C1;
	abTxBuffer[6].5 := x404_M9i_C2;

	xConnect:= TRUE; (* Open connection *)
	wState := 20;

20: (* Wait until connection is established *)
	IF oMbMaster.xIS_OPEN THEN
		xSend := TRUE; (* Send request to remote Modbus-Slave *)
		wState := 30;
	END_IF

30: (* Wait for response from remote Modbus-Slave *)
	IF NOT xSend THEN
		(* Check for errors *)
		IF oMbMaster.wERROR = 0 THEN
			(* Success*)
			wState := 40;
		ELSE
			(* Failed *)
			xValidValues := FALSE;
			wState := 999;
		END_IF
	END_IF

40: (* Map receive buffer data to fb's local outputs *)
	(* Format analog input data for 750-461:  16#F830==-200; 16#2134==+850 *)
	r461_M10_C1 := WORD_TO_REAL( SHL(BYTE_TO_WORD(abRxBuffer[1]), 8) OR BYTE_TO_WORD(abRxBuffer[0]) )/850;
	r461_M10_C2 := WORD_TO_REAL( SHL(BYTE_TO_WORD(abRxBuffer[3]), 8) OR BYTE_TO_WORD(abRxBuffer[2]) )/10;
	(* Assign digital input data *)
	x402_M6_C1 := abRxBuffer[4].0; (* First 402 Channel 1*)
	x402_M6_C2 := abRxBuffer[4].1; (* First 402 Channel 2*)
	x402_M6_C3 := abRxBuffer[4].2; (* First 402 Channel 3*)
	x402_M6_C4 := abRxBuffer[4].3; (* First 402 Channel 4*)
	x402_M7_C1 := abRxBuffer[4].4; (* 402 Channel 1*)
	x402_M7_C2 := abRxBuffer[4].5; (* 402 Channel 2*)
	x402_M7_C3 := abRxBuffer[4].6; (* 402 Channel 3*)
	x402_M7_C4 := abRxBuffer[4].7; (* 402 Channel 4*)
	x402_M8_C1 := abRxBuffer[5].0; (* 402 Channel 1*)
	x402_M8_C2 := abRxBuffer[5].1; (* 402 Channel 2*)
	x402_M8_C3 := abRxBuffer[5].2; (* 402 Channel 3*)
	x402_M8_C4 := abRxBuffer[5].3; (* 402 Channel 4*)
	x404_M9_C1 := abRxBuffer[5].4; (* 404 Channel 1*)
	x404_M9_C2 := abRxBuffer[5].5; (* 404 Channel 2*)

	xValidValues := TRUE;
	wState := 999;
ELSE
	wState := 0;
END_CASE
END_FUNCTION_BLOCK
