//This file was generated by the LASAL2 CodeGenerator  -- 
//Please, do not edit this file (it might be overwritten by the next generator run)

//{{LSL_DEFINES

#define SAFETY_UDP_MAX_SOCKETS                6     // Max number of socket

#define SAFETY_UDP_CLT_SEND_OK                0    // Send ok
#define SAFETY_UDP_CLT_INVALID_HANDLE        -1    // Invalid handle
#define SAFETY_UDP_CLT_NOT_OPEN              -2    // Socket is not open
#define SAFETY_UDP_CLT_SEND_FAILED           -3    // Send failed
#define SAFETY_UDP_CLT_SEND_BUFFER_FULL      -4    // Send buffer is full
#define SAFETY_UDP_CLT_DATA_TO_BIG           -5    // Data to big

#define SAFETY_UDP_MAXIMUM_SEGMENT_SIZE    1452    // Maximum of user data

#define SAFETY_UDP_TIMEOUT_OPENSOCKET    (1000)    //timeout for opening socket

#define SAFETY_UDP_RECEIVE_TIMEOUT          800

#define SAFETY_UDP_TX_BUFFER_SIZE          1024
//}}LSL_DEFINES

//{{LSL_DECLARATION

(*!
<Class
	Name               = "SafetyUDP"
	Revision           = "1.4"
	GUID               = "{5260DCC2-D171-4729-B965-8A7B43D0B86A}"
	RealtimeTask       = "false"
	CyclicTask         = "false"
	DefCyclictime      = "10 ms"
	BackgroundTask     = "false"
	DefBackground      = "always"
	Sigmatek           = "true"
	OSInterface        = "false"
	HighPriority       = "false"
	Automatic          = "false"
	UpdateMode         = "Prescan"
	IconPath           = ".\Class\Safety.ico"
	SharedCommandTable = "true"
	Objectsize         = "(514,120)"
	Comment            = "UDP Communication">
	<Channels>
		<Server Name="ClassState" GUID="{A6D9A0DC-20E2-414D-B902-67A7FC14ABB0}" Visualized="true" Initialize="false" WriteProtected="true" Retentive="false"/>
		<Server Name="InitFault" GUID="{231B5CBA-1263-4E96-AAF9-4D7D2F1C7CB6}" Visualized="false" Initialize="false" WriteProtected="true" Retentive="false" Comment="-1: opening error socket&#13;&#10;-2: opening socket timeout&#13;&#10;-3: bind error&#13;&#10;-4: ip-converting error&#13;&#10;-5: ip-reading error&#13;&#10;"/>
		<Server Name="InitSSM" GUID="{6D1952D9-FC8F-42D8-A44C-15A075C7A028}" Visualized="false" Initialize="false" WriteProtected="true" Retentive="false"/>
		<Server Name="sControl" GUID="{A970D83E-4CC8-4464-B7C5-A1CD5B19FEB3}" Visualized="false" Initialize="false" WriteProtected="true" Retentive="false" Comment="this server shows the UDP state"/>
		<Server Name="sErrorCount" GUID="{873197F2-33A7-4806-A999-3D24D4F6C9BB}" Visualized="true" Initialize="false" WriteProtected="true" Retentive="false" Comment="0 = no error&#13;&#10;1 = error"/>
		<Server Name="sLastErrorMessage" GUID="{94E630A5-6991-4FA1-AF39-605514F6C930}" Visualized="true" Initialize="false" WriteProtected="true" Retentive="false" Comment="  0 = _NO_ERROR_UDP_ERROR&#13;&#10; -1 = _INIT_TCP_USER_UDP_ERROR&#13;&#10; -2 = _NO_IP_ADDRESS_UDP_ERROR&#13;&#10; -3 = _NO_MEMORY_CONNECTION_UDP_ERROR&#13;&#10; -4 = _NO_MEMORY_SENDBUFFER_UDP_ERROR&#13;&#10; -5 = _INVALID_HANDLE_UDP_ERROR&#13;&#10; -6 = _SHUTDOWN_UDP_ERROR&#13;&#10; -7 = _CLOSESOCKET_UDP_ERROR&#13;&#10; -8 = _ALLOCATE_SOCKET_UDP_ERROR&#13;&#10; -9 = _SET_BIND_UDP_ERROR&#13;&#10;-10 = _RECV_UDP_ERROR&#13;&#10;-11 = _SEND_UDP_ERROR&#13;&#10;-12 = _NO_LOCAL_IP_UDP_ERROR&#13;&#10;-13 = _NO_DESTINATION_IP_UDP_ERROR"/>
		<Server Name="sLastErrorNoOS" GUID="{ED25AD73-138F-4A20-90C9-1E2204E795D3}" Visualized="true" Initialize="false" WriteProtected="true" Retentive="false" Comment="TCP_NOT_READY           -2000&#13;&#10;TCP_INVALID_SOCKSTATE   -2001&#13;&#10;TCP_NOMEM_ERROR         -2002&#13;&#10;TCP_BUFFER_TO_SMALL     -2003&#13;&#10;TCP_MAXSOCKETS_ERROR    -2004&#13;&#10;TCP_INVALID_SOCKNUM     -2005&#13;&#10;TCP_INVALID_NUMBER      -2007&#13;&#10;TCP_SYSTEM_ERROR        -2008&#13;&#10;TCP_NOIF_ERROR          -2009&#13;&#10;&#13;&#10;//getlasterror codes&#13;&#10;TCP_ADDR_NOT_AVAIL      -3000   //endpoint address not available&#13;&#10;TCP_ADDR_IN_USE         -3001   //address in use&#13;&#10;TCP_AF_NO_SUPPORT       -3002   //family not supported&#13;&#10;TCP_ARP_TABLE_FULL      -3003   //arp table full&#13;&#10;TCP_INVALID_BAUD        -3004   //invalid baud rate &#13;&#10;TCP_INVALID_COMM_PORT   -3005   //invalid comm port number&#13;&#10;TCP_INVALID_DEVICE      -3006   //invalid device type&#13;&#10;TCP_INVALID_IFACE       -3007   //invalid interface number&#13;&#10;TCP_INVALID_MASK        -3008   //invalid mask (ether must not be all fs)&#13;&#10;TCP_INVALID_PING        -3009   //invalid ping response&#13;&#10;TCP_CONN_REFUSED        -3010   //endpoint refused connection&#13;&#10;TCP_DEST_ADDR_REQ       -3011   //destination address is required&#13;&#10;TCP_DEST_UNREACH        -3012   //destination unreachable (ICMP)&#13;&#10;TCP_INVALID_PARAM       -3013   //invalid parameter (pointer is 0)&#13;&#10;TCP_IFACE_CLOSED        -3014   //interface closed&#13;&#10;TCP_IFACE_TABLE_FULL    -3015   //interface table full&#13;&#10;TCP_IFACE_OPEN_FAIL     -3016   //interface open failed&#13;&#10;TCP_IN_PROGRESS         -3017   //operation (connect) is in progress&#13;&#10;TCP_INVALID_FUNC        -3018   //invalid function call (parameter)&#13;&#10;TCP_SOCKET_CONNECTED    -3019   //socket is already connected&#13;&#10;TCP_MC_TABLE_FULL       -3020   //multicast table full&#13;&#10;TCP_MC_ADDR_NOT_FOUND   -3021   //multicast address not found&#13;&#10;TCP_OUT_OF_PORTS        -3022   //out of ports &#13;&#10;TCP_NET_DOWN            -3023   //network is down (send failed)&#13;&#10;TCP_NET_UNREACH         -3024   //network unreachable (keepalive failed)&#13;&#10;TCP_OUT_OF_DCUS         -3025   //out of DCUs (packets)&#13;&#10;TCP_OPTPARAM_INVALID    -3026   //option parameter is invalid&#13;&#10;TCP_SOCK_NOT_CONNECTED  -3027   //socket is not connected&#13;&#10;TCP_RTIP_NOT_INST       -3028   //RTIP not initialized (i.e. xn_rtip_init not called)&#13;&#10;TCP_INVALID_SOCKET      -3029   //invalid socket descriptor&#13;&#10;TCP_NUM_DEVICE          -3030   //not enough devices (see CFG_NUM_ED,CFG_NUM_SMCX, NUM_3C, NUM_RS232 etc)&#13;&#10;TCP_OP_NOT_SUPPORT      -3031   //socket type or specified operation not supported for this function&#13;&#10;TCP_OUTPUT_FULL         -3032   //send failed due to output list being full&#13;&#10;TCP_PROBE_FAIL          -3033   //could not determine device&#13;&#10;TCP_RENTRANT            -3034   //non-reentrancy error&#13;&#10;TCP_ROUTE_NOT_FOUND     -3035   //routing table entry not found&#13;&#10;TCP_ROUTE_FULL          -3036   //routing table full&#13;&#10;TCP_RSC_INIT_FAIL       -3037   //resource initialization failed&#13;&#10;TCP_SHUTDOWN            -3038   //illegal operation due to socket shutdown&#13;&#10;TCP_TIMEOUT             -3039   //timeout&#13;&#10;TCP_TYPE_NOT_SUPPORT    -3040   //type not supported (only SOCK_STREAM and SOCK_DGRAM are supported)&#13;&#10;TCP_WOULD_ARP           -3041   //send needs to ARP but ARP is disabled (see INCLUDE_ARP)&#13;&#10;TCP_WOULD_BLOCK         -3042   //socket non-blocking but function would block&#13;&#10;TCP_UNKNOWN_ERROR       -3043"/>
		<Server Name="sTReceive" GUID="{7CAED140-CC3D-4522-ABA2-481BB1FB661C}" Visualized="false" Initialize="false" WriteProtected="true" Retentive="false"/>
		<Client Name="InterfaceNo" Required="false" Internal="false" DefValue="1" Comment="If interface frames via IP address are used, this is the place to choose the interface number&#13;&#10;&#13;&#10;For example if you set the IP of interface 1 via autoexec.lsl setting SET IP 1 x.x.x.x and this is what you want to use, you choose 1 for the interface number."/>
		<Client Name="To_StdLib" Required="false" Internal="false" Comment="Object Channel to _StdLib, connected automatically "/>
		<Client Name="UdpSafetyPort" Required="false" Internal="false" DefValue="10823" Comment="If interface frames via IP address are used, this is the place to choose the port.&#13;&#10;It&apos;s recommended to only change the port (all communication partners must use the same port!) if there would be a conflict with the default port 10823."/>
	</Channels>
	<Dependencies>
		<Files>
			<File Path=".\Source\interfaces\lsl_st_tcp_user.h" Include="false"/>
		</Files>
	</Dependencies>
	<RevDoku>
		<Owner Company="Sigmatek" Author="RamAnd"/>
		<Dokumentation Revision="1.4" Date="02.03.2020" Author="FurDom" Company="Sigmatek" Description="Reworked to support newer CPUs (address space &gt; 0x80000000)"/>
		<Dokumentation Revision="1.3" Date="14.02.2019" Author="PieSte" Company="Sigmatek" Description="Numbers were assigned to the log messages to make them available in the help."/>
		<Dokumentation Revision="1.2" Date="06.03.2018" Author="EisMic" Company="Sigmatek" Description="Attached header files no longer point to the installation directory of LASAL but instead now point to the the source/interfaces folder."/>
		<Dokumentation Revision="1.1" Date="23.01.2018" Author="RamAnd" Company="Sigmatek" Description="Log messages have been standardized for easier maintenance, easier use in any class and to allow spam filtering. Code for the logging functions is now only located in HwControl."/>
		<Dokumentation Revision="1.0" Date="13.09.2016" Author="RamAnd" Company="Sigmatek" Description="First library version"/>
	</RevDoku>
</Class>
*)
SafetyUDP : CLASS
	TYPE
#pragma pack(push, 1)
	  _BUFFER_HEADER : STRUCT
	    DataSize : UDINT;
	  END_STRUCT;
#pragma pack(pop)
	  _FSM_CLT_STATE :
	  (
	    _STATE_INIT,
	    _STATE_WORK
	  )$UDINT;
	  _FSM_UDP_ERROR :  //! <Type Public="true" Name="_FSM_UDP_ERROR"/>
	  (
	    _NO_ERROR_UDP_ERROR:=0,
	    _INIT_TCP_USER_UDP_ERROR:=4294967295,
	    _NO_IP_ADDRESS_UDP_ERROR:=4294967294,
	    _NO_MEMORY_SOCKET_UDP_ERROR:=4294967293,
	    _NO_MEMORY_SENDBUFFER_UDP_ERROR:=4294967292,
	    _INVALID_HANDLE_UDP_ERROR:=4294967291,
	    _SHUTDOWN_UDP_ERROR:=4294967290,
	    _CLOSESOCKET_UDP_ERROR:=4294967289,
	    _ALLOCATE_SOCKET_UDP_ERROR:=4294967288,
	    _SET_BIND_UDP_ERROR:=4294967287,
	    _RECV_UDP_ERROR:=4294967286,
	    _SEND_UDP_ERROR:=4294967285,
	    _NO_LOCAL_IP_UDP_ERROR:=4294967284,
	    _NO_DESTINATION_IP_UDP_ERROR:=4294967283,
	    _INVALID_UDP_PORT_UDP_ERROR,
	    _INVALID_INTERFACE_NUMBER_UDP_ERROR,
	    _NO_MEMORY_RECEIVE_BUFFER_UDP_ERROR,
	    _NO_MEMORY_CONNECTION_BUFFER_UDP_ERROR
	  )$DINT;
	  _FSM_UDP_USER :  //! <Type Public="true" Name="_FSM_UDP_USER"/>
	  (
	    _STATE_INIT_UDP,
	    _STATE_IDLE_UDP,
	    _STATE_SOCK_UDP,
	    _STATE_CONNECT_UDP,
	    _STATE_ONLY_SEND_UDP,
	    _STATE_RECV_UDP,
	    _STATE_SEND_UDP,
	    _STATE_SHUTDOWN_UDP,
	    _STATE_CLOSE_SOCK_UDP,
	    _STATE_ERROR_UDP
	  )$UDINT;
	  _INITSTEPS :  //! <Type Public="true" Name="_INITSTEPS"/>
	  (
	    _NO_OPERATION,
	    _ADD_SOCKET,
	    _CHECK_IF_SOCKET_OPEN,
	    _BIND_SOCKET,
	    _CLOSE_CON
	  )$UDINT;
#pragma pack(push, 1)
	  _TX_RINGBUFFER : STRUCT  //! <Type Comment="struct to handle a ringbuffer" Name="_TX_RINGBUFFER"/>
	    udSize : UDINT;
	    udUsed : UDINT;
	    pMem : ^void;
	    pRead : ^void;
	    pWrite : ^void;
	  END_STRUCT;
#pragma pack(pop)
#pragma pack(push, 1)
	  _SOCKET : STRUCT
	    bInUse : BOOL;
	    szIPAddress : ARRAY [0..0x10] OF CHAR;
	    udPort : UDINT;
	    bOpen : BOOL;
	    dSocket : DINT;
	    FSM_UDP : _FSM_UDP_USER;
	    pCallbackThis : ^void;
	    pCallbackMeth : ^void;
	    SendBuffer : _TX_RINGBUFFER;
	    pNextSocket : ^_SOCKET;
	  END_STRUCT;
#pragma pack(pop)
#pragma pack(push, 1)
	  _UDP_CLT_SOCKETS : STRUCT
	    dActSocket : DINT;
	    pSockets : ^_SOCKET;
	  END_STRUCT;
#pragma pack(pop)
	  t_SingleLogs : BDINT
	  [
	    1 InvalidPortNbr,
	    2 InvalidIPAddr,
	    3 ComNotInitialized,
	    4 InvalidData,
	  ];
	END_TYPE
  //Servers:
	ClassState 	: SvrChCmd_DINT;
	sControl 	: SvrCh__FSM_UDP_USER_PTofCls_SafetyUDP;
	sErrorCount 	: SvrCh_DINT;
	sLastErrorMessage 	: SvrCh__FSM_UDP_ERROR_PTofCls_SafetyUDP;
	sLastErrorNoOS 	: SvrCh_DINT;
	InitSSM 	: SvrCh__INITSTEPS_PTofCls_SafetyUDP;
	InitFault 	: SvrCh_DINT;
	sTReceive 	: SvrCh_UDINT;
  //Clients:
	To_StdLib 	: CltChCmd__StdLib;
	UdpSafetyPort 	: CltCh_UDINT;
	InterfaceNo 	: CltCh_UDINT;
  //Variables:
		us_FirstScan 	: USINT;
		pActSocket 	: ^_SOCKET;			//! <Variable Comment="includes all Informations to the act Sockets" Name="pActSocket"/>
		FSMUDP 	: _FSM_CLT_STATE;			//! <Variable Comment="SSW for Connection" Name="FSMUDP"/>
		udSendError 	: UDINT;			//! <Variable Comment="Counter if sending Data failed" Name="udSendError"/>
		Sockets 	: _UDP_CLT_SOCKETS;			//! <Variable Comment="includes Informations to all Sockets" Name="Sockets"/>
		pTempData 	: ^CHAR;			//! <Variable Comment="actual received Data" Name="pTempData"/>
		lsl_tcp_user 	: ^LSL_TCP_USER;
		udDestinationIpAddress 	: UDINT;			//! <Variable Comment="Destination ip address" Name="udDestinationIpAddress"/>
		udDestinationPort 	: UDINT;			//! <Variable Comment="Destination port number" Name="udDestinationPort"/>
		RecCounter 	: UDINT;
		CyclicCounter 	: UDINT;
		TimeMark 	: UDINT;
		MaxTime 	: UDINT;
		pSocket 	: ^_SOCKET;
		TOpenSocket 	: UDINT;
		hdLocalIP 	: HDINT;
		chLocalIP : ARRAY [0..15] OF CHAR;

		CommInitialized 	: BOOL;
		pCallBackThisPtr 	: ^void;
		pCallBackMeth 	: ^void;
		bdSingleLogs 	: t_SingleLogs;
  //Functions:
	
	FUNCTION SafetyUDP
		VAR_OUTPUT
			ret_code 	: ConfStates;
		END_VAR;
				//! <Function Comment="-) initialize UDP/TCP USER pointer to use OS UDP/TCP FUNCTIONS&#13;&#10;-) read port number&#13;&#10;-) Allocate Memory for Buffers" Name="Init"/>
	FUNCTION VIRTUAL GLOBAL Init;
				//! <Function Comment="Cyclic call for main programm" Name="CyWork"/>
	FUNCTION VIRTUAL GLOBAL CyWork
		VAR_INPUT
			EAX 	: UDINT;
		END_VAR
		VAR_OUTPUT
			state (EAX) 	: UDINT;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL Background
		VAR_INPUT
			EAX 	: UDINT;
		END_VAR
		VAR_OUTPUT
			state (EAX) 	: UDINT;
		END_VAR;
				//! <Function Comment="Call this Function to add a socket for sending Data to a UDP user" Name="AddSocket"/>
	FUNCTION VIRTUAL GLOBAL AddSocket
		VAR_OUTPUT
			pSocket 	: ^_SOCKET;			//! <Variable Comment="Save this Handle to call the &quot;IsOpen&quot;,&quot;BindSocket&quot;, &quot;SendData&quot; and &quot;DelSocket&quot; Function" Name="AddSocket.pSocket"/>
		END_VAR;
				//! <Function Comment="Call this Function for receive Data from a UDP user" Name="BindSocket"/>
	FUNCTION VIRTUAL GLOBAL BindSocket
		VAR_INPUT
			pSocket 	: ^_SOCKET;			//! <Variable Comment="Handle" Name="BindSocket.pSocket"/>
			pIpAddress 	: ^CHAR;			//! <Variable Comment="Pointer to IP-Address&#13;&#10;Needs to be a dotted string!&#13;&#10;&#13;&#10;e.g. &quot;192.168.2.1&quot;Ip address" Name="BindSocket.pIpAddress"/>
			udPort 	: UDINT;			//! <Variable Comment="Port number" Name="BindSocket.udPort"/>
			pCallbackThis 	: ^void;			//! <Variable Comment="This Pointer to Object which should be called" Name="BindSocket.pCallbackThis"/>
			pCallbackMeth 	: ^void;			//! <Variable Comment="Pointer to Method which should be called" Name="BindSocket.pCallbackMeth"/>
		END_VAR
		VAR_OUTPUT
			dRetcode 	: DINT;			//! <Variable Comment=" 0 = _NO_ERROR_UDP_ERROR&#13;&#10;-2 = _NO_IP_ADDRESS_UDP_ERROR&#13;&#10;-5 = _INVALID_HANDLE_UDP_ERROR&#13;&#10;-9 = _SET_BIND_UDP_ERROR" Name="BindSocket.dRetcode"/>
		END_VAR;
				//! <Function Comment="this function writes data into the TX buffer&#13;&#10;&#13;&#10;the first 4 Bytes are always the size of the following Data" Name="RingbufferWrite"/>
	FUNCTION RingbufferWrite
		VAR_INPUT
			pBuffer 	: ^_TX_RINGBUFFER;
			pData 	: ^void;
			udSize 	: UDINT;
		END_VAR
		VAR_OUTPUT
			dRetcode 	: DINT;
		END_VAR;
				//! <Function Comment="this function reads data from the TX buffer" Name="RingbufferRead"/>
	FUNCTION RingbufferRead
		VAR_INPUT
			pBuffer 	: ^_TX_RINGBUFFER;
			pData 	: ^void;
			udSize 	: UDINT;
		END_VAR
		VAR_OUTPUT
			dRetcode 	: DINT;
		END_VAR;
				//! <Function Comment="Delete one Entry in SendBuffer" Name="FLUSHRingbuffer"/>
	FUNCTION VIRTUAL GLOBAL FLUSHRingbuffer
		VAR_INPUT
			pSocket 	: ^_SOCKET;			//! <Variable Comment="Handle what you get after calling &quot;AddSocket&quot;" Name="FLUSHRingbuffer.pSocket"/>
		END_VAR;
				//! <Function Comment="Function to send data over UDP&#13;&#10;" Name="SendData"/>
	FUNCTION VIRTUAL GLOBAL SendData
		VAR_INPUT
			pSocket 	: ^_SOCKET;			//! <Variable Comment="Handle what you get after calling &quot;AddSocket&quot;" Name="SendData.pSocket"/>
			pData 	: ^void;			//! <Variable Comment="Pointer to Data" Name="SendData.pData"/>
			udSize 	: UDINT;			//! <Variable Comment="Size of Data" Name="SendData.udSize"/>
			bDirect 	: BOOL;			//! <Variable Comment="0 ... Write it to Send Buffer and send it in next cycle&#13;&#10;1 ... Send it immediately" Name="SendData.bDirect"/>
			udIpAddress 	: UDINT;			//! <Variable Comment="Ip adress UDINT format" Name="SendData.udIpAddress"/>
			udPort 	: UDINT;			//! <Variable Comment="Port number" Name="SendData.udPort"/>
		END_VAR
		VAR_OUTPUT
			dRetcode 	: DINT;			//! <Variable Comment=" 0 = TCP_CLT_SEND_OK         &#13;&#10;-1 = TCP_CLT_INVALID_HANDLE  &#13;&#10;-2 = TCP_CLT_NOT_CONNECTED   &#13;&#10;-3 = TCP_CLT_SEND_FAILED     &#13;&#10;-4 = TCP_CLT_SEND_BUFFER_FULL&#13;&#10;-5 = TCP_CLT_DATA_TO_BIG     &#13;&#10;" Name="SendData.dRetcode"/>
		END_VAR;
				//! <Function Comment="initialize connection structure" Name="INITSocket"/>
	FUNCTION INITSocket
		VAR_INPUT
			pSocket 	: ^_SOCKET;
		END_VAR;
				//! <Function Comment="Call this Function to check if a socket is open and the Handle will be saved" Name="IsOpen"/>
	FUNCTION VIRTUAL GLOBAL IsOpen
		VAR_INPUT
			pSocket 	: ^_SOCKET;			//! <Variable Comment="Handle from &quot;AddSocket&quot;" Name="IsOpen.pSocket"/>
		END_VAR
		VAR_OUTPUT
			bRetcode 	: BOOL;			//! <Variable Comment="0 = not connected&#13;&#10;1 = connected" Name="IsOpen.bRetcode"/>
		END_VAR;
				//! <Function Comment="Delete a socket" Name="DelSocket"/>
	FUNCTION VIRTUAL GLOBAL DelSocket
		VAR_INPUT
			pSocket 	: ^_SOCKET;			//! <Variable Comment="Handle from &quot;AddSocket&quot;" Name="DelSocket.pSocket"/>
		END_VAR;
				//! <Function Comment="checks the Handle for validity" Name="CheckHandleValid"/>
	FUNCTION CheckHandleValid
		VAR_INPUT
			pCheckSocket 	: ^_SOCKET;
		END_VAR
		VAR_OUTPUT
			bRetcode 	: BOOL;
		END_VAR;
				//! <Function Comment="send Data via OS-Function" Name="SendUDP"/>
	FUNCTION SendUDP
		VAR_INPUT
			pSocket 	: ^_SOCKET;
			pData 	: ^CHAR;
			udSize 	: UDINT;
			udTimeout 	: UDINT;
			udIpAddress 	: UDINT;
			udPort 	: UDINT;
		END_VAR
		VAR_OUTPUT
			dRetcode 	: DINT;
		END_VAR;
				//! <Function Comment="Set error bit, message and OS error" Name="SetError"/>
	FUNCTION SetError
		VAR_INPUT
			bError 	: BOOL;			//! <Variable Comment="Error bit" Name="SetError.bError"/>
			ErrorMessage 	: _FSM_UDP_ERROR;			//! <Variable Comment="Set error message" Name="SetError.ErrorMessage"/>
			dError 	: DINT;			//! <Variable Comment="Set error number from OS" Name="SetError.dError"/>
		END_VAR;
				//! <Function Comment="Convert the ip address from string to UDINT format" Name="ConvertStrToUdint"/>
	FUNCTION GLOBAL ConvertStrToUdint
		VAR_INPUT
			pIpAddress 	: ^CHAR;			//! <Variable Comment="Pointer to IP-Address&#13;&#10;Needs to be a dotted string!&#13;&#10;&#13;&#10;e.g. &quot;192.168.2.1&quot;Ip address" Name="ConvertStrToUdint.pIpAddress"/>
		END_VAR
		VAR_OUTPUT
			udIpAddress 	: UDINT;			//! <Variable Comment="Ip address UDINT format&#13;&#10;0xFFFFFFFF = error" Name="ConvertStrToUdint.udIpAddress"/>
		END_VAR;
				//! <Function Comment="Convert the ip address from UDINT to string format" Name="ConvertUdintToStr"/>
	FUNCTION GLOBAL ConvertUdintToStr
		VAR_INPUT
			pIpAddress 	: ^CHAR;			//! <Variable Comment="Pointer to IP-Address&#13;&#10;Needs to be a dotted string!&#13;&#10;&#13;&#10;e.g. &quot;192.168.2.1&quot;Ip address" Name="ConvertUdintToStr.pIpAddress"/>
			udLen 	: UDINT;			//! <Variable Comment="Length of string" Name="ConvertUdintToStr.udLen"/>
			udIpAddress 	: UDINT;			//! <Variable Comment="Ip address in UDINT format" Name="ConvertUdintToStr.udIpAddress"/>
		END_VAR
		VAR_OUTPUT
			dRetval 	: DINT;			//! <Variable Comment="    0 = NO ERROR&#13;&#10;-3000 = TCP_ADDR_NOT_AVAIL                         &#13;&#10;-3001 = TCP_ADDR_IN_USE&#13;&#10;-3002 = TCP_AF_NO_SUPPORT&#13;&#10;-3003 = TCP_ARP_TABLE_FULL&#13;&#10;-3004 = TCP_INVALID_BAUD&#13;&#10;-3005 = TCP_INVALID_COMM_PORT&#13;&#10;-3006 = TCP_INVALID_DEVICE&#13;&#10;-3007 = TCP_INVALID_IFACE&#13;&#10;-3008 = TCP_INVALID_MASK&#13;&#10;-3009 = TCP_INVALID_PING&#13;&#10;-3010 = TCP_CONN_REFUSED&#13;&#10;-3011 = TCP_DEST_ADDR_REQ&#13;&#10;-3012 = TCP_DEST_UNREACH&#13;&#10;-3013 = TCP_INVALID_PARAM&#13;&#10;-3014 = TCP_IFACE_CLOSED&#13;&#10;-3015 = TCP_IFACE_TABLE_FULL&#13;&#10;-3016 = TCP_IFACE_OPEN_FAIL&#13;&#10;-3017 = TCP_IN_PROGRESS&#13;&#10;-3018 = TCP_INVALID_FUNC&#13;&#10;-3019 = TCP_SOCKET_CONNECTED&#13;&#10;-3020 = TCP_MC_TABLE_FULL&#13;&#10;-3021 = TCP_MC_ADDR_NOT_FOUND&#13;&#10;-3022 = TCP_OUT_OF_PORTS&#13;&#10;-3023 = TCP_NET_DOWN&#13;&#10;-3024 = TCP_NET_UNREACH&#13;&#10;-3025 = TCP_OUT_OF_DCUS&#13;&#10;-3026 = TCP_OPTPARAM_INVALID&#13;&#10;-3027 = TCP_SOCK_NOT_CONNECTED&#13;&#10;-3028 = TCP_RTIP_NOT_INST&#13;&#10;-3029 = TCP_INVALID_SOCKET&#13;&#10;-3030 = TCP_NUM_DEVICE&#13;&#10;-3031 = TCP_OP_NOT_SUPPORT&#13;&#10;-3032 = TCP_OUTPUT_FULL&#13;&#10;-3033 = TCP_PROBE_FAIL&#13;&#10;-3034 = TCP_RENTRANT&#13;&#10;-3035 = TCP_ROUTE_NOT_FOUND&#13;&#10;-3036 = TCP_ROUTE_FULL&#13;&#10;-3037 = TCP_RSC_INIT_FAIL&#13;&#10;-3038 = TCP_SHUTDOWN&#13;&#10;-3039 = TCP_TIMEOUT&#13;&#10;-3040 = TCP_TYPE_NOT_SUPPORT&#13;&#10;-3041 = TCP_WOULD_ARP&#13;&#10;-3042 = TCP_WOULD_BLOCK&#13;&#10;-3043 = TCP_UNKNOWN_ERROR&#13;&#10;" Name="ConvertUdintToStr.dRetval"/>
		END_VAR;
				//! <Function Comment="Get ip info&#13;&#10;&#13;&#10;IP_OPT_ADDR              1&#13;&#10;IP_OPT_SUBNETMASK        2&#13;&#10;IP_OPT_ETHERNET_ADDR     3&#13;&#10;IP_OPT_GATEWAY           4&#13;&#10;IP_OPT_PORT              5" Name="GetIpInfo"/>
	FUNCTION GLOBAL GetIpInfo
		VAR_INPUT
			pIpInfo 	: ^UDINT;			//! <Variable Comment="Information" Name="GetIpInfo.pIpInfo"/>
			dPara 	: DINT;			//! <Variable Comment="IP_OPT_ADDR              1&#13;&#10;IP_OPT_SUBNETMASK        2&#13;&#10;IP_OPT_ETHERNET_ADDR     3&#13;&#10;IP_OPT_GATEWAY           4&#13;&#10;IP_OPT_PORT              5" Name="GetIpInfo.dPara"/>
			dInterface 	: DINT;			//! <Variable Comment="Interface 1 or 2" Name="GetIpInfo.dInterface"/>
		END_VAR
		VAR_OUTPUT
			dRetval 	: DINT;			//! <Variable Comment="    0 = NO ERROR&#13;&#10;-3000 = TCP_ADDR_NOT_AVAIL                         &#13;&#10;-3001 = TCP_ADDR_IN_USE&#13;&#10;-3002 = TCP_AF_NO_SUPPORT&#13;&#10;-3003 = TCP_ARP_TABLE_FULL&#13;&#10;-3004 = TCP_INVALID_BAUD&#13;&#10;-3005 = TCP_INVALID_COMM_PORT&#13;&#10;-3006 = TCP_INVALID_DEVICE&#13;&#10;-3007 = TCP_INVALID_IFACE&#13;&#10;-3008 = TCP_INVALID_MASK&#13;&#10;-3009 = TCP_INVALID_PING&#13;&#10;-3010 = TCP_CONN_REFUSED&#13;&#10;-3011 = TCP_DEST_ADDR_REQ&#13;&#10;-3012 = TCP_DEST_UNREACH&#13;&#10;-3013 = TCP_INVALID_PARAM&#13;&#10;-3014 = TCP_IFACE_CLOSED&#13;&#10;-3015 = TCP_IFACE_TABLE_FULL&#13;&#10;-3016 = TCP_IFACE_OPEN_FAIL&#13;&#10;-3017 = TCP_IN_PROGRESS&#13;&#10;-3018 = TCP_INVALID_FUNC&#13;&#10;-3019 = TCP_SOCKET_CONNECTED&#13;&#10;-3020 = TCP_MC_TABLE_FULL&#13;&#10;-3021 = TCP_MC_ADDR_NOT_FOUND&#13;&#10;-3022 = TCP_OUT_OF_PORTS&#13;&#10;-3023 = TCP_NET_DOWN&#13;&#10;-3024 = TCP_NET_UNREACH&#13;&#10;-3025 = TCP_OUT_OF_DCUS&#13;&#10;-3026 = TCP_OPTPARAM_INVALID&#13;&#10;-3027 = TCP_SOCK_NOT_CONNECTED&#13;&#10;-3028 = TCP_RTIP_NOT_INST&#13;&#10;-3029 = TCP_INVALID_SOCKET&#13;&#10;-3030 = TCP_NUM_DEVICE&#13;&#10;-3031 = TCP_OP_NOT_SUPPORT&#13;&#10;-3032 = TCP_OUTPUT_FULL&#13;&#10;-3033 = TCP_PROBE_FAIL&#13;&#10;-3034 = TCP_RENTRANT&#13;&#10;-3035 = TCP_ROUTE_NOT_FOUND&#13;&#10;-3036 = TCP_ROUTE_FULL&#13;&#10;-3037 = TCP_RSC_INIT_FAIL&#13;&#10;-3038 = TCP_SHUTDOWN&#13;&#10;-3039 = TCP_TIMEOUT&#13;&#10;-3040 = TCP_TYPE_NOT_SUPPORT&#13;&#10;-3041 = TCP_WOULD_ARP&#13;&#10;-3042 = TCP_WOULD_BLOCK&#13;&#10;-3043 = TCP_UNKNOWN_ERROR" Name="GetIpInfo.dRetval"/>
		END_VAR;
	
	FUNCTION VIRTUAL LogError
		VAR_INPUT
			e_msg 	: ^CHAR;
		END_VAR;
	
	FUNCTION VIRTUAL LogValue
		VAR_INPUT
			pString 	: ^CHAR;
			Value 	: UDINT;
			Value2 	: UDINT := 16#FFFFFFFF;
			Value3 	: UDINT := 16#FFFFFFFF;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL InitComm;
	
	FUNCTION GLOBAL AddCallBackInfo
		VAR_INPUT
			pThis 	: ^void;
			pCBMeth 	: ^void;
		END_VAR;
	
	FUNCTION VIRTUAL GLOBAL CyclicCall;
	
	FUNCTION VIRTUAL GLOBAL SendUDPData
		VAR_INPUT
			pData 	: ^void;
			udLength 	: UDINT;
			udIPAddr 	: UDINT;
		END_VAR
		VAR_OUTPUT
			retcode 	: DINT;
		END_VAR;
  //Tables:
	FUNCTION @STD
		VAR_OUTPUT
			ret_code	: CONFSTATES;
		END_VAR;
	FUNCTION GLOBAL TAB @CT_;
END_CLASS;

#pragma usingLtd _StdLib


//}}LSL_DECLARATION


FUNCTION GLOBAL TAB SafetyUDP::@CT_
0$UINT,
2#0100000000000000$UINT, //TY_SAFETYUDP
1$UINT, 4$UINT, (SIZEOF(::SafetyUDP))$UINT, 
8$UINT, 3$UINT, 0$UINT, 
TO_UDINT(3727715967), "SafetyUDP", //Class
TO_UDINT(0), 0, 0$UINT, 0$UINT, //Baseclass
//Servers:
(::SafetyUDP.ClassState.pMeth)$UINT, _CH_CMD$UINT, 2#0000000000000000$UINT, TO_UDINT(1096059024), "ClassState", 
(::SafetyUDP.sControl.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(4051248739), "sControl", 
(::SafetyUDP.sErrorCount.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(4265969349), "sErrorCount", 
(::SafetyUDP.sLastErrorMessage.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(2401811376), "sLastErrorMessage", 
(::SafetyUDP.sLastErrorNoOS.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(1503396177), "sLastErrorNoOS", 
(::SafetyUDP.InitSSM.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(2669708630), "InitSSM", 
(::SafetyUDP.InitFault.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(1074126952), "InitFault", 
(::SafetyUDP.sTReceive.pMeth)$UINT, _CH_SVR$UINT, 2#0000000000000000$UINT, TO_UDINT(2984281204), "sTReceive", 
//Clients:
(::SafetyUDP.To_StdLib.pCh)$UINT, _CH_CLT_OBJ$UINT, 2#0000000000000000$UINT, TO_UDINT(2139173287), "To_StdLib", TO_UDINT(3689364044), "_StdLib", 2$UINT, 0$UINT, 
(::SafetyUDP.UdpSafetyPort.pCh)$UINT, _CH_CLT_DATA$UINT, 2#0000000000000000$UINT, TO_UDINT(3294470351), "UdpSafetyPort", 
(::SafetyUDP.InterfaceNo.pCh)$UINT, _CH_CLT_DATA$UINT, 2#0000000000000000$UINT, TO_UDINT(2005113602), "InterfaceNo", 
END_FUNCTION


#define USER_CNT_SafetyUDP 12

TYPE
	_LSL_STD_VMETH	: STRUCT
			CmdTable	: CMDMETH;
			UserFcts	: ARRAY[0..USER_CNT_SafetyUDP] OF ^Void;
	END_STRUCT;
END_TYPE

FUNCTION SafetyUDP::@STD
	VAR_OUTPUT
		ret_code	: CONFSTATES;
	END_VAR
	VAR
		vmt	: _LSL_STD_VMETH;
	END_VAR

	//Command Methods
	InitCmdTable (nCmd := nSTDCMD + USER_CNT_SafetyUDP, pCmd := #vmt.CmdTable);
	vmt.CmdTable.Init		:= #Init();
	vmt.CmdTable.CyWork		:= #CyWork();
#pragma warning (disable : 74)
	vmt.UserFcts[0]		:= #Background();

#pragma warning (default : 74)
#pragma warning (disable : 74)
	vmt.UserFcts[1]		:= #AddSocket();

#pragma warning (default : 74)
#pragma warning (disable : 74)
	vmt.UserFcts[2]		:= #BindSocket();

#pragma warning (default : 74)
#pragma warning (disable : 74)
	vmt.UserFcts[3]		:= #FLUSHRingbuffer();

#pragma warning (default : 74)
#pragma warning (disable : 74)
	vmt.UserFcts[4]		:= #SendData();

#pragma warning (default : 74)
#pragma warning (disable : 74)
	vmt.UserFcts[5]		:= #IsOpen();

#pragma warning (default : 74)
#pragma warning (disable : 74)
	vmt.UserFcts[6]		:= #DelSocket();

#pragma warning (default : 74)
#pragma warning (disable : 74)
	vmt.UserFcts[7]		:= #LogError();

#pragma warning (default : 74)
#pragma warning (disable : 74)
	vmt.UserFcts[8]		:= #LogValue();

#pragma warning (default : 74)
#pragma warning (disable : 74)
	vmt.UserFcts[9]		:= #InitComm();

#pragma warning (default : 74)
#pragma warning (disable : 74)
	vmt.UserFcts[10]		:= #CyclicCall();

#pragma warning (default : 74)
#pragma warning (disable : 74)
	vmt.UserFcts[11]		:= #SendUDPData();

#pragma warning (default : 74)
	ClassState.pMeth		:= StoreCmd (pCmd := #vmt.CmdTable, SHARED);

	IF ClassState.pMeth THEN
		ret_code	:= C_OK;
	ELSE
		ret_code	:= C_OUTOF_NEAR;
		RETURN;
	END_IF;
	ret_code	:= SafetyUDP();

END_FUNCTION

//{{LSL_IMPLEMENTATION
// Method define because we need poiner to method
FUNCTION GLOBAL Callback
VAR_INPUT
  pData       : ^void;
  udSize      : UDINT;
  udIpAddress : UDINT;
  udPort      : UDINT;
END_VAR;


FUNCTION VIRTUAL GLOBAL SafetyUDP::Init

  //##################################################################################
  //### Initialization
  //##################################################################################

  us_FirstScan += 1;

  if us_FirstScan = 1 then
    UdpSafetyPort := UdpSafetyPort.Read();
  
    // check port number
    if UdpSafetyPort = 0 then
      SetError(bError:=TRUE, ErrorMessage:=_INVALID_UDP_PORT_UDP_ERROR, dError:=0);
      LogError("@04D9 (SafetyUDP::Init) Invalid UDP Port");
    end_if;
    
    InterfaceNo := InterfaceNo.Read();

    // check interface number
    if InterfaceNo = 0 then
      SetError(bError:=TRUE, ErrorMessage:=_INVALID_INTERFACE_NUMBER_UDP_ERROR, dError:=0);
      LogError("@04DA (SafetyUDP::Init) Invalid interface number");
    end_if;

    // allocate receive buffer
    pTempData$pVoid := To_StdLib.Malloc(size:= SAFETY_UDP_MAXIMUM_SEGMENT_SIZE);
    if pTempData then
      _memset(dest:=pTempData, usByte:=0, cntr:=SAFETY_UDP_MAXIMUM_SEGMENT_SIZE);
    else
      SetError(bError:=TRUE, ErrorMessage:=_NO_MEMORY_RECEIVE_BUFFER_UDP_ERROR, dError:=0);
      LogError("@04DB (SafetyUDP::Init) Failed to allocate memory for receive buffer");
    end_if;


//  elsif us_FirstScan = 12 then
  elsif _FirstScan then

    //set ssm to initialize udp-communication
    InitSSM := _ADD_SOCKET;
    CommInitialized := FALSE;

    if OS_CILGET("TCP_USER", #lsl_tcp_user) then 
      lsl_tcp_user  := NIL;
      SetError(bError:= TRUE, ErrorMessage:= _INIT_TCP_USER_UDP_ERROR, dError:= 0);
    end_if;
  end_if;
  
END_FUNCTION


FUNCTION SafetyUDP::INITSocket
	VAR_INPUT
		pSocket 	: ^_SOCKET;
	END_VAR

  //##################################################################################
  //### Initialize socket structure
  //##################################################################################

  pSocket^.bInUse := false;
  _memset(dest:= #pSocket^.szIPAddress[0], usByte:= 0x00, cntr:= 0x10);
  pSocket^.udPort        := 0;
  pSocket^.bOpen         := false;
  pSocket^.dSocket       := 0;
  pSocket^.FSM_UDP       := _STATE_IDLE_UDP;
  pSocket^.pCallbackMeth := NIL;
  pSocket^.pCallbackThis := NIL;
  pSocket^.pNextSocket   := NIL;

END_FUNCTION


FUNCTION VIRTUAL GLOBAL SafetyUDP::AddSocket
	VAR_OUTPUT
		pSocket 	: ^_SOCKET;
	END_VAR
  VAR
    i             : SINT;     // help variable for loop
    pSearchSocket : ^_SOCKET; // help pointer
  END_VAR

  //##################################################################################
  //### Add socket
  //##################################################################################
  pSocket           := NIL;

  if (Sockets.dActSocket < SAFETY_UDP_MAX_SOCKETS) then

    //###################################################################################
    //### Allocate memory for socket structure
    //###################################################################################
    pSocket$^void := To_StdLib.Malloc(size:= sizeof(_SOCKET));

    if (pSocket = NIL) then
      SetError(bError:= TRUE, ErrorMessage:= _NO_MEMORY_SOCKET_UDP_ERROR, dError:= 0);
      RETURN;
    end_if;


    //###################################################################################
    //### Allocate memory for send buffer (RINGBUFFER)
    //###################################################################################
 
    pSocket^.SendBuffer.pMem := To_StdLib.Malloc(size:= SAFETY_UDP_TX_BUFFER_SIZE);

    if (pSocket^.SendBuffer.pMem = NIL) then
      To_StdLib.Free(mptr:= pSocket);
      SetError(bError:= TRUE, ErrorMessage:= _NO_MEMORY_SENDBUFFER_UDP_ERROR, dError:= 0);
      RETURN;
    end_if;
      

    //###################################################################################
    //### Initialize send buffer (RINGBUFFER)
    //###################################################################################
    pSocket^.SendBuffer.udSize := SAFETY_UDP_TX_BUFFER_SIZE;
    pSocket^.SendBuffer.udUsed := 0;
    pSocket^.SendBuffer.pRead  := pSocket^.SendBuffer.pMem;
    pSocket^.SendBuffer.pWrite := pSocket^.SendBuffer.pMem;


    //###################################################################################
    //### Initialize socket structure
    //###################################################################################
    INITSocket(pSocket:= pSocket);

    Sockets.dActSocket += 1;
    
    //###################################################################################
    //### Add socket
    //###################################################################################
    if (Sockets.pSockets = NIL) then
    
      Sockets.pSockets     := pSocket;
      pSocket^.pNextSocket := pSocket;
      
    else
    
      i             := 1;
      pSearchSocket := Sockets.pSockets;

      while i < (Sockets.dActSocket - 1) do
        pSearchSocket := pSearchSocket^.pNextSocket;
        i += 1;
      end_while;

      pSearchSocket^.pNextSocket := pSocket;
      pSocket^.pNextSocket       := Sockets.pSockets;
      
    end_if;    
  end_if;

END_FUNCTION


FUNCTION VIRTUAL GLOBAL SafetyUDP::BindSocket
	VAR_INPUT
		pSocket 	: ^_SOCKET;
		pIpAddress 	: ^CHAR;
		udPort 	: UDINT;
		pCallbackThis 	: ^void;
		pCallbackMeth 	: ^void;
	END_VAR
	VAR_OUTPUT
		dRetcode 	: DINT;
	END_VAR
  VAR
    udIpAddress : UDINT;    // help variable for ip address
  END_VAR

  //##################################################################################
  //### Add receive buffer to socket
  //##################################################################################
  
  if (pSocket = NIL) then
    SetError(bError:= TRUE, ErrorMessage:= _INVALID_HANDLE_UDP_ERROR, dError:= 0);
    dRetcode := _INVALID_HANDLE_UDP_ERROR;
    RETURN;
  end_if;
  
  if (pIpAddress = NIL) then
    SetError(bError:= TRUE, ErrorMessage:= _NO_IP_ADDRESS_UDP_ERROR, dError:= 0);
    dRetcode := _NO_IP_ADDRESS_UDP_ERROR;
    RETURN;
  end_if;

  _strcpy(dest:= #pSocket^.szIPAddress[0], src:= pIpAddress);
  pSocket^.udPort        := udPort;
  pSocket^.pCallbackThis := pCallbackThis;
  pSocket^.pCallbackMeth := pCallbackMeth;

  udIpAddress := OS_TCP_USER_STRTOULONG(pIpAddress);

  dRetcode := OS_UDP_USER_BIND(pSocket^.dSocket,
                               udIpAddress,
                               udPort);

  if (dRetcode < 0) then
  
    if (dRetcode <> TCP_NOT_READY) then
      SetError(bError:= TRUE, ErrorMessage:= _SET_BIND_UDP_ERROR, dError:= dRetcode);
      pSocket^.FSM_UDP := _STATE_SHUTDOWN_UDP;                          // set FSM to shut down main socket
    end_if;
    
  elsif (dRetcode = 0) then
  
    pSocket^.FSM_UDP := _STATE_RECV_UDP;    //changed from pActSocket to pSocket - correction from _UDP V1.1; no effect on behaviour
    
  end_if;

END_FUNCTION


FUNCTION VIRTUAL GLOBAL SafetyUDP::DelSocket
	VAR_INPUT
		pSocket 	: ^_SOCKET;
	END_VAR
  VAR
    pSearchSocket : ^_SOCKET; // help pointer
    i             : SINT;     // help variable for loop
    dRet          : DINT;     // help variable for return value
  END_VAR

  //##################################################################################
  //### Delete socket
  //##################################################################################

  if (CheckHandleValid(pSocket) = false) then //### invalid pointer
    SetError(bError:= TRUE, ErrorMessage:= _INVALID_HANDLE_UDP_ERROR, dError:= 0);
    RETURN;
  end_if;

  pSearchSocket := Sockets.pSockets;

  for i := 0 to (Sockets.dActSocket - 1) do
  
    if (pSearchSocket^.pNextSocket = pSocket) then

      //###################################################################################
      //### Correct socket pointer
      //###################################################################################
      pSearchSocket^.pNextSocket := pSocket^.pNextSocket;
      if (pSocket = Sockets.pSockets) then
        Sockets.pSockets := pSocket^.pNextSocket;
      end_if;
            
      dRet := OS_TCP_USER_CLOSESOCKET(pSocket^.dSocket, 0);      // Close Socket //spimar 1.3 --> 20.3.2012
      if (dRet < 0) then
        SetError(bError:= TRUE, ErrorMessage:= _CLOSESOCKET_UDP_ERROR, dError:= dRet);
      end_if;

      //###################################################################################
      //### Free memory for send buffer & connection structure
      //###################################################################################
      if (pSocket^.SendBuffer.pMem <> NIL) then // spimar 1.3 --> 20.3.2012
        To_StdLib.Free(mptr:= pSocket^.SendBuffer.pMem);
      end_if;

      To_StdLib.Free(mptr:= pSocket);

      Sockets.dActSocket -= 1;
      if (Sockets.dActSocket = 0) then
        Sockets.pSockets := NIL;
        FSMUDP           := _STATE_INIT;
        sControl         := _STATE_INIT_UDP;
      end_if;
      
      EXIT;
      
    end_if;
    
    pSearchSocket := pSearchSocket^.pNextSocket;
    
  end_for;

END_FUNCTION


FUNCTION VIRTUAL GLOBAL SafetyUDP::SendData
	VAR_INPUT
		pSocket 	: ^_SOCKET;
		pData 	: ^void;
		udSize 	: UDINT;
		bDirect 	: BOOL;
		udIpAddress 	: UDINT;
		udPort 	: UDINT;
	END_VAR
	VAR_OUTPUT
		dRetcode 	: DINT;
	END_VAR
  VAR
    BufferHeader  : _BUFFER_HEADER; // help variable for header
    dRet          : DINT;           // help variable for return value
  END_VAR  

  //##################################################################################
  //### Send data
  //##################################################################################

  if (udSize <= SAFETY_UDP_MAXIMUM_SEGMENT_SIZE) then          // Check if Data is not to big

    dRetcode := SAFETY_UDP_CLT_SEND_FAILED;

    if (CheckHandleValid(pSocket) = false) then         // Check pointer
      dRetcode := SAFETY_UDP_CLT_INVALID_HANDLE;
      RETURN;
    end_if;

    if (pSocket^.bOpen = false) then                    // Check socket
      dRetcode := SAFETY_UDP_CLT_NOT_OPEN;
      RETURN;
    end_if;

    udDestinationIpAddress := udIpAddress;
    udDestinationPort      := udPort;

    if (bDirect = true) then

      //#########################################################################################
      //### send data via OS function
      //#########################################################################################
      dRet := SendUDP(pSocket    := pSocket,
                      pData      := pData$^CHAR,
                      udSize     := udSize,
                      udTimeout  := 0,
                      udIpAddress:= udDestinationIpAddress,
                      udPort     := udDestinationPort);

      if (dRet = udSize$DINT) then
        dRetcode := SAFETY_UDP_CLT_SEND_OK;
      end_if;
      
    else

      //#########################################################################################
      //### put data into send buffer and send it in next cycle
      //#########################################################################################
      if ((pSocket^.SendBuffer.udSize - pSocket^.SendBuffer.udUsed) < (udSize + sizeof(_BUFFER_HEADER))) then
        dRetcode := SAFETY_UDP_CLT_SEND_BUFFER_FULL;
        RETURN;
      end_if;

      BufferHeader.DataSize := udSize;

      dRet := RingbufferWrite(pBuffer:= #pSocket^.SendBuffer,
                              pData  := #BufferHeader,
                              udSize := sizeof(_BUFFER_HEADER));

      if (dRet <> sizeof(_BUFFER_HEADER)) then
        RETURN;
      end_if;

      dRet := RingbufferWrite(pBuffer:= #pSocket^.SendBuffer,
                              pData  := pData,
                              udSize := BufferHeader.DataSize);

      if (dRet = BufferHeader.DataSize$DINT) then
        dRetcode := SAFETY_UDP_CLT_SEND_OK;
      end_if;
    end_if;
    
  else
  
    dRetcode := SAFETY_UDP_CLT_DATA_TO_BIG;                    // Give Error that Data is to big
    
  end_if;

END_FUNCTION


FUNCTION SafetyUDP::RingbufferRead
	VAR_INPUT
		pBuffer 	: ^_TX_RINGBUFFER;
		pData 	: ^void;
		udSize 	: UDINT;
	END_VAR
	VAR_OUTPUT
		dRetcode 	: DINT;
	END_VAR
  VAR
    udBytes2End : UDINT;  // help variable
    udBytesTmp  : UDINT;  // help variable
  END_VAR

  //##################################################################################
  //### Ring buffer read
  //##################################################################################

  dRetcode := 0;

  if (pBuffer = NIL) | (pData = NIL) | (pBuffer^.pMem = NIL) then
    RETURN; //### invalid pointer
  end_if;

  udBytes2End := (pBuffer^.pMem$UDINT + pBuffer^.udSize) - pBuffer^.pRead$UDINT;

  if (udSize > udBytes2End) then 

    //##########################################################################################
    //### we must read the data in 2 blocks (|second|...........other data...........|first|)
    //##########################################################################################
    _memcpy(ptr1:= pData, ptr2:= pBuffer^.pRead, cntr:= udBytes2End); //### copy the first block
    pData          += udBytes2End;
    pBuffer^.pRead := pBuffer^.pMem$^USINT;
    udBytesTmp     := udSize - udBytes2End;
    _memcpy(ptr1:= pData, ptr2:= pBuffer^.pRead, cntr:= udBytesTmp); //### copy the second block
    pBuffer^.pRead += udBytesTmp;

  else

    //##########################################################################################
    //### read data in one block
    //##########################################################################################
    _memcpy(ptr1:= pData, ptr2:= pBuffer^.pRead, cntr:= udSize);
    pBuffer^.pRead += udSize;
    
  end_if;

  pBuffer^.udUsed -= udSize;        // decrease the number of bytes in ringbuffer
  dRetcode        := udSize$DINT;

END_FUNCTION


FUNCTION SafetyUDP::RingbufferWrite
	VAR_INPUT
		pBuffer 	: ^_TX_RINGBUFFER;
		pData 	: ^void;
		udSize 	: UDINT;
	END_VAR
	VAR_OUTPUT
		dRetcode 	: DINT;
	END_VAR
  VAR
    udBytes2End : UDINT;  // help variable
    udBytesTmp  : UDINT;  // help variable
  END_VAR

  //##################################################################################
  //### Ring buffer write
  //##################################################################################

  dRetcode := 0;

  if (pBuffer = NIL) | (pData = NIL) | (pBuffer^.pMem = NIL) then
    RETURN; //### invalid pointer
  end_if;

  if ((udSize) > (pBuffer^.udSize - pBuffer^.udUsed)) then
    RETURN; //### buffer full
  end_if;

  udBytes2End := (pBuffer^.pMem$UDINT + pBuffer^.udSize) - pBuffer^.pWrite$UDINT; // calculate number of bytes till the end of SENDbuffer

  if (udSize > udBytes2End) then
    
    //##########################################################################################
    //### we must write the data in 2 blocks  (|second|...........other data...........|first|)
    //##########################################################################################
    _memcpy(ptr1:= pBuffer^.pWrite, ptr2:= pData, cntr:= udBytes2End); // copy the first block
    pData           += udBytes2End;
    pBuffer^.pWrite := pBuffer^.pMem$^USINT;
    udBytesTmp      := udSize - udBytes2End;
    _memcpy(ptr1:= pBuffer^.pWrite, ptr2:= pData, cntr:= udBytesTmp); // copy the second block
    pBuffer^.pWrite += udBytesTmp;
    
  else
    
    //##########################################################################################
    //### store data in one block
    //##########################################################################################
    _memcpy(ptr1:= pBuffer^.pWrite, ptr2:= pData, cntr:= udSize);
    pBuffer^.pWrite += udSize;
    
  end_if;
  
  pBuffer^.udUsed += udSize; // increase the number of bytes in ringbuffer
  dRetcode        := udSize$DINT;

END_FUNCTION


FUNCTION VIRTUAL GLOBAL SafetyUDP::FLUSHRingbuffer
	VAR_INPUT
		pSocket 	: ^_SOCKET;
	END_VAR
  VAR
    pBuffer : ^_TX_RINGBUFFER;  // help pointer
  END_VAR

  //##################################################################################
  //### Delete entry in send buffer
  //##################################################################################

  //*******************************************************
  if (CheckHandleValid(pSocket) = true) then
  
    pBuffer         := #pSocket^.SendBuffer;
    pBuffer^.pRead  := pBuffer^.pMem;
    pBuffer^.pWrite := pBuffer^.pMem;
    pBuffer^.udUsed := 0;
    
  end_if;
  //********************************************************
 
END_FUNCTION

FUNCTION VIRTUAL GLOBAL SafetyUDP::CyWork
	VAR_INPUT
		EAX 	: UDINT;
	END_VAR
	VAR_OUTPUT
		state (EAX) 	: UDINT;
	END_VAR
  
  //##################################################################################
  //### Cyclic call for main programm
  //##################################################################################

  CyclicCall();
  
  
  if (CommInitialized = FALSE) & UdpSafetyPort then
    InitComm();   
  end_if;
    
 	state := READY;

END_FUNCTION


FUNCTION VIRTUAL GLOBAL SafetyUDP::IsOpen
	VAR_INPUT
		pSocket 	: ^_SOCKET;
	END_VAR
	VAR_OUTPUT
		bRetcode 	: BOOL;
	END_VAR

  //##################################################################################
  //### Socket state
  //##################################################################################

  bRetcode := false;

  if (CheckHandleValid(pSocket) = true) then
    bRetcode := pSocket^.bOpen;
  end_if;

END_FUNCTION


FUNCTION SafetyUDP::CheckHandleValid
	VAR_INPUT
		pCheckSocket 	: ^_SOCKET;
	END_VAR
	VAR_OUTPUT
		bRetcode 	: BOOL;
	END_VAR
  VAR
    i       : USINT;    // help variable for loop
    pSocket : ^_SOCKET;
  END_VAR

  //##################################################################################
  //### Check handle
  //##################################################################################

  bRetcode := false;
  
  pSocket := Sockets.pSockets;
  
  i := 0;

  if (pCheckSocket <> NIL) then //### NIL pointer
  
    while i < Sockets.dActSocket do
    
      if (pSocket = pCheckSocket) then

        bRetcode := true;
        EXIT;
      else          
        pSocket := pSocket^.pNextSocket;
        i       += 1;
      end_if;
   
    end_while;
  end_if;

END_FUNCTION


FUNCTION SafetyUDP::SendUDP
	VAR_INPUT
		pSocket 	: ^_SOCKET;
		pData 	: ^CHAR;
		udSize 	: UDINT;
		udTimeout 	: UDINT;
		udIpAddress 	: UDINT;
		udPort 	: UDINT;
	END_VAR
	VAR_OUTPUT
		dRetcode 	: DINT;
	END_VAR

  //##################################################################################
  //### Send data
  //##################################################################################

  dRetcode := OS_TCP_USER_SENDTO(pSocket^.dSocket,
                                 pData,
                                 udSize,
                                 0, //### flags ... not used
                                 udTimeout,
                                 udIpAddress,
                                 udPort);

  if (dRetcode <> udSize$DINT) then
  
  // Error send
    udSendError += 1;
    SetError(bError:= TRUE, ErrorMessage:= _SEND_UDP_ERROR, dError:= dRetcode);
  end_if;

END_FUNCTION


FUNCTION SafetyUDP::SetError
	VAR_INPUT
		bError 	: BOOL;
		ErrorMessage 	: _FSM_UDP_ERROR;
		dError 	: DINT;
	END_VAR

  //##################################################################################
  //### Set server and log error
  //##################################################################################

  sLastErrorMessage := ErrorMessage;
  sLastErrorNoOS    := dError;
  if bError then
    sErrorCount     += 1;
    LogValue("@04DC (SafetyUDP::SetError) Error at UDP occured! ErrorMessage: 0x{0}, OS Returncode: 0x{1}", Value:=ErrorMessage$UDINT, Value2:=dError$UDINT);
  end_if;

END_FUNCTION


FUNCTION GLOBAL SafetyUDP::ConvertStrToUdint
	VAR_INPUT
		pIpAddress 	: ^CHAR;
	END_VAR
	VAR_OUTPUT
		udIpAddress 	: UDINT;
	END_VAR

  //##################################################################################
  //### Convert the ip address from string to UDINT format
  //##################################################################################

  udIpAddress := OS_TCP_USER_STRTOULONG(pIpAddress);

END_FUNCTION


FUNCTION GLOBAL SafetyUDP::ConvertUdintToStr
	VAR_INPUT
		pIpAddress 	: ^CHAR;
		udLen 	: UDINT;
		udIpAddress 	: UDINT;
	END_VAR
	VAR_OUTPUT
		dRetval 	: DINT;
	END_VAR
  
  //##################################################################################
  //### Convert the ip address from UDINT to string format
  //##################################################################################
  
  dRetval := OS_TCP_USER_ULONGTOSTR(pIpAddress, udLen, udIpAddress);

END_FUNCTION


FUNCTION GLOBAL SafetyUDP::GetIpInfo
	VAR_INPUT
		pIpInfo 	: ^UDINT;
		dPara 	: DINT;
		dInterface 	: DINT;
	END_VAR
	VAR_OUTPUT
		dRetval 	: DINT;
	END_VAR

  //##################################################################################
  //### Get ip info
  //##################################################################################

  dRetval := OS_TCP_USER_IPINFO(dInterface, dPara, pIpInfo);

END_FUNCTION


FUNCTION VIRTUAL GLOBAL SafetyUDP::Background
	VAR_INPUT
		EAX 	: UDINT;
	END_VAR
	VAR_OUTPUT
		state (EAX) 	: UDINT;
	END_VAR
  
  cywork(EAX);
	state := READY;

END_FUNCTION

#pragma warning(disable: 73);
FUNCTION VIRTUAL SafetyUDP::LogError
	VAR_INPUT
		e_msg 	: ^CHAR;
	END_VAR
  
#ifdef HWC_LogError
  HWC_LogError(this, e_msg);
#endif

END_FUNCTION


FUNCTION VIRTUAL SafetyUDP::LogValue
	VAR_INPUT
		pString 	: ^CHAR;
		Value 	: UDINT;
		Value2 	: UDINT;(* := 16#FFFFFFFF *)
		Value3 	: UDINT;(* := 16#FFFFFFFF *)
	END_VAR

#ifdef HWC_LogValue3
  HWC_LogValue3(this, pString, Value, Value2, Value3);
#endif
  
END_FUNCTION
#pragma warning(default: 73);

FUNCTION VIRTUAL GLOBAL SafetyUDP::InitComm
  VAR
  	dRetcode : DINT;
  END_VAR

  case InitSSM of
    //wait for sending a command
    _NO_OPERATION:
    
    //add a socket 
    _ADD_SOCKET:
        
      InitFault := 0;
    
      //check if no socket is open
      if pSocket <> NIL then
        //close socket
        DelSocket(pSocket);
      end_if;
      
      pSocket := AddSocket();
      
      //control if openeing was successful
      if (pSocket <> NIL ) then
        //success, ready for binding socket
        TOpenSocket := ops.tAbsolute;
        InitSSM := _CHECK_IF_SOCKET_OPEN;
      else
        InitFault := -1;
        InitSSM := _CLOSE_CON;
        LogError("@0368 (SafetyUDP::InitComm) Failed to open socket");
      end_if;


    //check if socket is open
    _CHECK_IF_SOCKET_OPEN:
    
      if IsOpen(pSocket) & ((ops.tAbsolute - TOpenSocket) < SAFETY_UDP_TIMEOUT_OPENSOCKET) then
        
        //bind socket to receive only if we got a receive port
        if UdpSafetyPort > 0 then
          InitSSM := _BIND_SOCKET;
        else
          CommInitialized := TRUE;
          InitSSM := _NO_OPERATION;
        end_if;

        
      elsif ((ops.tAbsolute - TOpenSocket) > SAFETY_UDP_TIMEOUT_OPENSOCKET) then
        InitFault := -2;
        InitSSM := _CLOSE_CON;
        LogError("@0369 (SafetyUDP::InitComm) Timeout on opening socket");
      end_if;    

    //bind socket for receiving data
    _BIND_SOCKET:  

      //get local ip-address, needed for binding socket
      dRetcode := GetIpInfo(#hdLocalIP, IP_OPT_ADDR, InterfaceNo$DINT);
      
      //check if we got local ip: 0 = NO ERROR
      if ( dRetcode = 0 ) then
        //convert local ip to a string
        dRetcode := ConvertUdintToStr(#chLocalIP[0], sizeof(chLocalIP), hdLocalIP);
        
        //check if converting was successful
        if ( dRetcode = 0 ) then
          //bind socket to local ip-address
          dRetcode := BindSocket(pSocket, #chLocalIP[0], to_UDINT(UdpSafetyPort), pCallBackThisPtr, pCallBackMeth); 
          
          //check if binding was successful
          if ( dRetcode >= 0 ) then
            CommInitialized := TRUE;

            InitSSM := _NO_OPERATION;
    
          else
            //binding error
            InitFault := -3;
            InitSSM := _CLOSE_CON;
            LogError("@036B (SafetyUDP::InitComm) Error while binding socket to receive port! Check the chosen UDP port");
          end_if;
        else
          //ip-converting error
          InitFault := -4;
          InitSSM := _CLOSE_CON;
          LogError("@036C (SafetyUDP::InitComm) Error while converting local ip-address!");
        end_if;
      else
        //ip-reading error
        InitFault := -5;
        InitSSM := _CLOSE_CON;
        LogError("@036D (SafetyUDP::InitComm) Error while reading local ip-address! Check the selected interface number!");
      end_if;    
      
    _CLOSE_CON:
      //close connection on InitFault
      if pSocket <> NIL then
        DelSocket(pSocket);
      end_if;

      InitSSM := _NO_OPERATION;
      
    end_case;

END_FUNCTION


FUNCTION GLOBAL SafetyUDP::AddCallBackInfo
	VAR_INPUT
		pThis 	: ^void;
		pCBMeth 	: ^void;
	END_VAR

  if pThis <> NIL then
    if pCBMeth <> NIL then
      pCallBackThisPtr := pThis;
      pCallBackMeth := pCBMeth;
    else
      LogError("@04DD (SafetyUDP::AddCallBackInfo) Invalid callback-method");
    end_if;
  else
    LogError("@04DE (SafetyUDP::AddCallBackInfo) Invalid this-pointer");
  end_if;
  
END_FUNCTION


FUNCTION VIRTUAL GLOBAL SafetyUDP::CyclicCall
  VAR
    dRet          : DINT;           // help variable for return value
    pTmpThis      : ^SafetyUDP;   // help pointer to class
    pTmpFunc      : ^void;
    pTmpData      : ^void;          // help pointer to actual data
    tmpIpAddr     : UDINT;
    tmpPort       : UDINT;
    BufferHeader  : _BUFFER_HEADER; // help variable for header
    tmpStartRec : UDINT;
    tmpEndRec : UDINT;
  END_VAR

  //##################################################################################
  //### Main programm
  //##################################################################################

  //**********************************************************************************
  // Start FSMUDP 
  //**********************************************************************************
  case FSMUDP of

    //--------------------------------------------------------------------------------
    _STATE_INIT: // initialization state
    //--------------------------------------------------------------------------------

      if (lsl_tcp_user <> NIL) then
      
        if (Sockets.dActSocket) then  
          pActSocket := Sockets.pSockets;
          FSMUDP     := _STATE_WORK;
        else
          pActSocket := NIL;
        end_if;
        
      end_if;
     

    //--------------------------------------------------------------------------------
    _STATE_WORK: // work state
    //--------------------------------------------------------------------------------

      //##############################################################################
      //##                                                                          ##
      //##    this finite state machine is used for the main UDP socket:            ##
      //##                                                                          ##
      //##    -> allocate sockets                                                   ##
      //##    -> bind a port to a specified socket                                  ##
      //##    -> receive data from server                                           ##
      //##    -> disable receives and sends on socket                               ##
      //##    -> close socket                                                       ##
      //##                                                                          ##
      //##############################################################################
      
      //******************************************************************************
      // Start pActSocket^.FSM_UDP 
      //******************************************************************************
      case pActSocket^.FSM_UDP of

        //----------------------------------------------------------------------------
        _STATE_IDLE_UDP: // idle state
        //----------------------------------------------------------------------------

          if (pActSocket^.bOpen = false) then
            pActSocket^.FSM_UDP := _STATE_SOCK_UDP;
          end_if;


        //----------------------------------------------------------------------------
        _STATE_SOCK_UDP: // allocate socket
        //----------------------------------------------------------------------------

          pActSocket^.dSocket := OS_UDP_USER_SOCKET();

          if (pActSocket^.dSocket < 0) then
          // Error add socket
            SetError(bError:= TRUE, ErrorMessage:= _ALLOCATE_SOCKET_UDP_ERROR, dError:= pActSocket^.dSocket);
            pActSocket^.FSM_UDP := _STATE_ERROR_UDP;
            
          else
          // Add socket OK  
//            SetError(bError:= 0, ErrorMessage:= _NO_ERROR_UDP_ERROR, dError:= 0);
            
            pActSocket^.bOpen   := true;
            pActSocket^.FSM_UDP := _STATE_ONLY_SEND_UDP;
            
          end_if;          
        
        //----------------------------------------------------------------------------
        _STATE_ONLY_SEND_UDP: // only send state
        //----------------------------------------------------------------------------  

          if (pActSocket^.SendBuffer.udUsed) then
            pActSocket^.FSM_UDP := _STATE_SEND_UDP;
          end_if;


        //----------------------------------------------------------------------------
        _STATE_RECV_UDP: // receive state
        //----------------------------------------------------------------------------            
          
            tmpStartRec := OS_READMICROSEC();
          
          repeat
          
            
        
            dRet := OS_TCP_USER_RECVFROM(pActSocket^.dSocket,
                                         pTempData,
                                         SAFETY_UDP_MAXIMUM_SEGMENT_SIZE,
                                         0,
                                         0,
                                         #tmpIpAddr,
                                         #tmpPort);
            
            
            tmpEndRec := OS_READMICROSEC();
            sTReceive := tmpEndRec - tmpStartRec;
                            
            
            CyclicCounter += 1;
            
            if (dRet > 0) then
            // Receive data OK          
              if (ops.tAbsolute - TimeMark) > MaxTime then
                MaxTime := to_udint(ops.tAbsolute - TimeMark);
              end_if;

              RecCounter += 1;
              
              pTmpData := pTempData;
              
              pTmpFunc := pActSocket^.pCallbackMeth;
              pTmpThis := this;
              this$^void := pActSocket^.pCallbackThis;
              
              
              pTmpFunc$Callback(pData       := pTmpData,  
                                udSize      := dRet$UDINT,
                                udIpAddress := tmpIpAddr,
                                udPort      := tmpPort);
                          
                          
              this := pTmpThis;
              
              SetError(bError:= 0, ErrorMessage:= _NO_ERROR_UDP_ERROR, dError:= 0);   
              
            else
            // Error receive data
              if (dRet <> TCP_NOT_READY) then
                SetError(bError:= 1, ErrorMessage:= _RECV_UDP_ERROR, dError:= dRet);
              else
                TimeMark := ops.tAbsolute;
              end_if;
              
            end_if;
            
            
          
          until (dRet <= 0) | ((tmpEndRec - tmpStartRec) > SAFETY_UDP_RECEIVE_TIMEOUT) end_repeat; 
          
          
          //##########################################################
          //### Send data from ringbuffer
          //##########################################################
          if (pActSocket^.FSM_UDP = _STATE_RECV_UDP) then
            if (pActSocket^.SendBuffer.udUsed) then
              pActSocket^.FSM_UDP := _STATE_SEND_UDP;
            end_if;
          end_if;

        //----------------------------------------------------------------------------
        _STATE_SEND_UDP: // send data
        //----------------------------------------------------------------------------

          //##########################################################
          //### read message header from ringbuffer
          //##########################################################
          RingbufferRead(pBuffer:= #pActSocket^.SendBuffer,
                         pData  := #BufferHeader,
                         udSize := sizeof(_BUFFER_HEADER));

          //##########################################################
          //### read message from ringbuffer
          //##########################################################
          RingbufferRead(pBuffer:= #pActSocket^.SendBuffer,
                         pData  := pTempData,
                         udSize := BufferHeader.DataSize);

          //##########################################################
          //### send data via OS function
          //##########################################################
          dRet := SendUDP(pSocket    := pActSocket,
                          pData      := pTempData,
                          udSize     := BufferHeader.DataSize,
                          udTimeout  := 0,
                          udIpAddress:= udDestinationIpAddress,
                          udPort     := udDestinationPort);

          if (dRet = BufferHeader.DataSize$DINT) then
          // All data sent from ringbuffer
            if (pActSocket^.pCallbackMeth <> NIL) then
              pActSocket^.FSM_UDP := _STATE_RECV_UDP;
            else
              pActSocket^.FSM_UDP := _STATE_ONLY_SEND_UDP;
            end_if;
            
          end_if;


        //----------------------------------------------------------------------------
        _STATE_SHUTDOWN_UDP: // disable receives and sends on socket
        //----------------------------------------------------------------------------

          dRet :=  OS_TCP_USER_SHUTDOWN(pActSocket^.dSocket, 2);
          if (dRet < 0) then
          // Error shutdown socket
            SetError(bError:= 1, ErrorMessage:= _SHUTDOWN_UDP_ERROR, dError:= dRet);
          else
          // Shutdown socket OK
            SetError(bError:= 0, ErrorMessage:= _NO_ERROR_UDP_ERROR, dError:= 0);
          end_if;
          pActSocket^.FSM_UDP := _STATE_CLOSE_SOCK_UDP;


        //----------------------------------------------------------------------------
        _STATE_CLOSE_SOCK_UDP: // close socket
        //----------------------------------------------------------------------------

          dRet := OS_TCP_USER_CLOSESOCKET(pActSocket^.dSocket, 0);
          if (dRet < 0) then
          // Error close socket
            SetError(bError:= 1, ErrorMessage:= _CLOSESOCKET_UDP_ERROR, dError:= dRet);
          else
          // Close socket OK
            SetError(bError:= 0, ErrorMessage:= _NO_ERROR_UDP_ERROR, dError:= 0);
          end_if;
          pActSocket^.dSocket := 0;
          pActSocket^.bOpen   := false;
          pActSocket^.FSM_UDP := _STATE_IDLE_UDP;


        //----------------------------------------------------------------------------
        _STATE_ERROR_UDP: // error state
        //----------------------------------------------------------------------------


      end_case;      
      //******************************************************************************
      // End pActSocket^.FSM_UDP 
      //******************************************************************************
      
      // Actual state
      sControl := pActSocket^.FSM_UDP;
      // Set pointer to next socket
      pActSocket := pActSocket^.pNextSocket;

  end_case;
  //**********************************************************************************
  // End FSMUDP 
  //**********************************************************************************
  
END_FUNCTION


FUNCTION VIRTUAL GLOBAL SafetyUDP::SendUDPData
	VAR_INPUT
		pData 	: ^void;
		udLength 	: UDINT;
		udIPAddr 	: UDINT;
	END_VAR
	VAR_OUTPUT
		retcode 	: DINT;
	END_VAR

  retcode := -1;

  if pData <> NIL then
  
    if CommInitialized = TRUE then 
    
      if udIPAddr > 0 then
      
        //if we got no send-port -> send data via receive port
        if UdpSafetyPort > 0 then
          retcode := SendData(pSocket, pData, udLength, TRUE, udIpAddr, UdpSafetyPort);
        else
          if bdSingleLogs.InvalidPortNbr = FALSE then
            bdSingleLogs.InvalidPortNbr := TRUE;
            LogError("@0370 (SafetyUDP::SendUDPData) [SL] Port cannot be 0");
          end_if;
        end_if;
      else
        if bdSingleLogs.InvalidIPAddr = FALSE then
          bdSingleLogs.InvalidIPAddr := TRUE;
          LogError("@0371 (SafetyUDP::SendUDPData) [SL] IP address cannot be 0");
        end_if;
      end_if;
    else
      if bdSingleLogs.ComNotInitialized = FALSE then
        bdSingleLogs.ComNotInitialized := TRUE;
        LogError("@04DF (SafetyUDP::SendUDPData) [SL] Communication is not initialized");
      end_if;
    end_if;
  else
    if bdSingleLogs.InvalidData = FALSE then
      bdSingleLogs.InvalidData := TRUE;
      LogError("@0372 (SafetyUDP::SendUDPData) [SL] Invalid data");
    end_if;
  end_if;

END_FUNCTION


FUNCTION SafetyUDP::SafetyUDP
	VAR_OUTPUT
		ret_code 	: ConfStates;
	END_VAR

#ifdef HWC_LogInit
  HWC_LogInit();
#endif

	ret_code := C_OK;

END_FUNCTION
