TCP IP Communication between Beijer HMI and other Devices

Discussion of configuring and troubleshooting communication to PLC's or other devices using iX Developer.
ajack
Posts: 44
Joined: Wed Feb 22, 2012 12:01 am

TCP IP Communication between Beijer HMI and other Devices

Post by ajack »

Hi all,

I would like to point out my current obstacle as below:
  • - I'm currently using another device support TCP/IP Communication and successfully connect between my laptop (using Hercules or HyperTerminal to send/receive data.
    - However, I could NOT find TCP IP communication in iX Developer.
May I know what could be the solutions?

Thanks all!

AMitchneck
Posts: 137
Joined: Mon Jun 11, 2012 2:10 pm

Re: TCP IP Communication between Beijer HMI and other Device

Post by AMitchneck »

Hi ajack,

TCP IP just indicates the connection is over Ethernet. What is the underlying communication protocol? Based on your mention of hyperterminal I'm assuming it's ascii-based like telnet.
Adam M.
Controls Engineer
FlexEnergy

ajack
Posts: 44
Joined: Wed Feb 22, 2012 12:01 am

Re: TCP IP Communication between Beijer HMI and other Device

Post by ajack »

AMitchneck wrote:Hi ajack,

TCP IP just indicates the connection is over Ethernet. What is the underlying communication protocol? Based on your mention of hyperterminal I'm assuming it's ascii-based like telnet.
Hi Adam,

Thanks so much for your response!

Yes, you're correct, the underlying communication protocol is ASCII-based. Moreover, I purely want to capture or send data with RAW Ethernet TCP/IP. Is that possible?

Thanks,

AMitchneck
Posts: 137
Joined: Mon Jun 11, 2012 2:10 pm

Re: TCP IP Communication between Beijer HMI and other Device

Post by AMitchneck »

Hi ajack,

You can do that by creating a custom script module and using a Socket. For example, below I have included the source code for a ModbusTCP client I created to read holding registers.

you will need to add the following using's to the head of your script module:
using System.Net;
using System.Net.Sockets;

To use the client you would do something like:

Code: Select all

using (ModClient client = new ModClient())
{
	client.Connect(host, port);
	client.ReadHoldingRegisters(slave, address, 2, out buffer);
}
Note this method makes a new connection every time the client is used, then closes it.

Code: Select all

	public class ModClient : IDisposable
	{
		private volatile Socket sock;
		private ushort transID;
		
		public ModClient()
		{
			sock = null;
			transID = 0;
		}
		public bool Connect(string host, int port)
		{
			Socket _sock = null;
			IPEndPoint ModAddr;
			
			Close(); // clean up any previous connection
			transID = 0;
			
			try { ModAddr = new IPEndPoint(IPAddress.Parse(host), port); }
			catch (ArgumentNullException) { return false; }
			catch (ArgumentOutOfRangeException) { return false; }
			catch (FormatException) { return false; }
			
			try
			{
				_sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
				AsyncState asyncState = new AsyncState(_sock);
				_sock.BeginConnect(ModAddr, ProcessConnect, asyncState);
				if (asyncState.WaitForReturn(20000))
				{
					if (_sock.Connected)
					{
						sock = _sock;
						return true;
					}
				}
			}
			catch (SocketException) { }
			catch (ObjectDisposedException) { }
			catch
			{
				// unknown error, close socket and throw error
				if (_sock != null) _sock.Close();
				_sock = null;
				throw;
			}
			
			// connection failed, close socket
			if (_sock != null) _sock.Close();
			return false;
		}
		private void ProcessConnect(IAsyncResult asyncResult)
		{
			AsyncState asyncState = (AsyncState)(asyncResult.AsyncState);
			try { asyncState.socket.EndConnect(asyncResult); }
			catch (SocketException) { }
			catch (ArgumentException) { }
			catch (InvalidOperationException) { }
			finally { asyncState.Set(); }
		}
		
		public bool Connected
		{
			get
			{
				if (sock == null) return false;
				return sock.Connected;
			}
		}
		
		public void Close()
		{
			Socket _sock = sock;
			if (_sock == null) return;
			sock = null;
			
			try { if (_sock.Connected) _sock.Shutdown(SocketShutdown.Both); }
			catch (SocketException) { }
			catch (ObjectDisposedException) { }
			catch (PlatformNotSupportedException) { }
			finally { _sock.Close(); }
		}
		public void Dispose()
		{
			Close();
		}
		
		public int ReadHoldingRegisters(ushort address, ushort registers, out byte[] buffer)
		{
			return ReadHoldingRegisters(1, address, registers, out buffer);
		}
		public int ReadHoldingRegisters(byte slave, ushort address, ushort registers, out byte[] buffer)
		{
			registers--;
			if ((registers >= 125) || ((0xFFFF - registers) < address))
			{
				buffer = null;
				return -1;
			}
			
			byte[] header, inbuff, outbuff;
			int length, i;
			ushort thisID = transID++;
			outbuff = new byte[12];
			
			registers++;
			buffer = new byte[registers * 2];
			if (!Connected) return -1;
			
			outbuff[0] = (byte)((thisID & 0xFF00) >> 8);
			outbuff[1] = (byte)(thisID & 0x00FF);
			outbuff[2] = 0;
			outbuff[3] = 0;
			outbuff[4] = 0;
			outbuff[5] = 6;
			outbuff[6] = slave;
			outbuff[7] = 3;
			outbuff[8] = (byte)((address & 0xFF00) >> 8);
			outbuff[9] = (byte)(address & 0x00FF);
			outbuff[10] = (byte)((registers & 0xFF00) >> 8);
			outbuff[11] = (byte)(registers & 0x00FF);
			if (!SendAll(outbuff)) return -1;
			
			for (; ; )
			{
				if (!ReceiveAll(out header, 8)) return -1;
				length = (int)((((ushort)header[4]) << 8) | (ushort)header[5]) - 2;
				if (length < 0)
				{
					Close();
					return -1;
				}
				if (!ReceiveAll(out inbuff, length)) return -1;
				
				if ((outbuff[0] == header[0]) && (outbuff[1] == header[1]) && (outbuff[7] == (header[7] & 0x7F)))
				{
					if ((header[7] & 0x80) != 0)
					{
						if (length == 0)
							buffer[0] = 0;
						else
							buffer[0] = inbuff[0];
						return 0;
					}
					if ((length - 1) < buffer.Length)
					{
						buffer[0] = 0;
						return 0;
					}
					for (i = 0; i < buffer.Length; i++)
					{
						buffer[i] = inbuff[i + 1];
					}
					return (int)registers;
				}
			}
		}
		
		private bool SendAll(byte[] buffer)
		{
			int i, bytesSent;
			
			if (buffer == null) throw new ArgumentNullException("buffer");
			if (!Connected) return false;
			
			AsyncState asyncState = new AsyncState(sock);
			for (i = 0; i < buffer.Length; i += bytesSent)
			{
				try
				{
					if (sock.Poll(5000000, SelectMode.SelectWrite)) // use send timeout of 5 seconds
					{
						asyncState.Reset();
						sock.BeginSend(buffer, i, buffer.Length - i, SocketFlags.None, ProcessSend, asyncState);
						if (asyncState.WaitForReturn(10000)) // use send timeout of 10 seconds
							bytesSent = asyncState.result;
						else
							bytesSent = 0; // send timed out
					}
					else
					{
						bytesSent = 0; // send timed out
					}
				}
				catch (SocketException) { bytesSent = 0; }
				catch (ObjectDisposedException) { bytesSent = 0; }
				if (bytesSent == 0)
				{
					// no data sent -> connection lost
					Close(); // close socket
					return false;
				}
			}
			
			return true;
		}
		private void ProcessSend(IAsyncResult asyncResult)
		{
			AsyncState asyncState = (AsyncState)(asyncResult.AsyncState);
			try { asyncState.result = asyncState.socket.EndSend(asyncResult); }
			catch (SocketException) { asyncState.result = 0; }
			catch (ArgumentException) { asyncState.result = 0; }
			catch (InvalidOperationException) { asyncState.result = 0; }
			finally { asyncState.Set(); }
		}
		
		private bool ReceiveAll(out byte[] buffer, int size)
		{
			int i, bytesRecv;
			
			if (size < 0)
			{
				buffer = null;
				return false;
			}
			else
			{
				buffer = new byte[size];
				if (!Connected) return false;
			}
			
			for (i = 0; i < size; i += bytesRecv)
			{
				try
				{
					if (sock.Poll(5000000, SelectMode.SelectRead)) // use receive timeout of 5 seconds
						bytesRecv = sock.Receive(buffer, i, size - i, SocketFlags.None);
					else
						bytesRecv = 0; // receive timed out
				}
				catch (SocketException) { bytesRecv = 0; }
				catch (ObjectDisposedException) { bytesRecv = 0; }
				if (bytesRecv == 0)
				{
					// no data received -> connection lost
					Close(); // close socket
					return false;
				}
			}
			
			return true;
		}
		
		private class AsyncState
		{
			private Socket sock;
			private System.Threading.ManualResetEvent evnt = new System.Threading.ManualResetEvent(false);
			public int result = 0;
			
			public AsyncState(Socket socket)
			{
				sock = socket;
			}
			public Socket socket
			{
				get { return sock; }
			}
			public void Set()
			{
				evnt.Set();
			}
			public void Reset()
			{
				evnt.Reset();
			}
			public bool WaitForReturn(int timeout)
			{
				return evnt.WaitOne(timeout, false);
			}
		}
	}
Adam M.
Controls Engineer
FlexEnergy

ajack
Posts: 44
Joined: Wed Feb 22, 2012 12:01 am

Re: TCP IP Communication between Beijer HMI and other Device

Post by ajack »

Hi Adam,

Thanks so much for your effort to provide detail Script!

Can I conclude that currently iX doesn't provide Raw Communication through TCP/IP? And, we need to handle in lower level so that we can capture and sending data through Socket of Ethernet Port?

Moreover, may I know whether you can provide the file with the script so that I can quickly implement in my program now?
It may cost some time for me to read through all this code before implementation...

Thanks,
Phong Duong

AMitchneck
Posts: 137
Joined: Mon Jun 11, 2012 2:10 pm

Re: TCP IP Communication between Beijer HMI and other Device

Post by AMitchneck »

I don't work for Beijer so you'd have to contact customer support to get exact answer, but as far as I know there is no raw communication driver.

What I could send you as a scripting module would only be a direct copy of what I attached in my prior response. The code was more for example of how you could use/manage the Socket.
Adam M.
Controls Engineer
FlexEnergy

ajack
Posts: 44
Joined: Wed Feb 22, 2012 12:01 am

Re: TCP IP Communication between Beijer HMI and other Device

Post by ajack »

AMitchneck wrote:I don't work for Beijer so you'd have to contact customer support to get exact answer, but as far as I know there is no raw communication driver.

What I could send you as a scripting module would only be a direct copy of what I attached in my prior response. The code was more for example of how you could use/manage the Socket.
Hi Adam,

Thanks so much for your help!

ajack
Posts: 44
Joined: Wed Feb 22, 2012 12:01 am

Re: TCP IP Communication between Beijer HMI and other Device

Post by ajack »

Hi Adam,

Thanks for your help! I can do some simple communication between PC and HMI using Script C# with Socket class.

I would like to ask for some more questions:

1. Should we choose Asynchronous or Synchronous socket connection?

2. Where should we put main loop in HMI code? Or we can use ScreenOpened?

3. If we insert Script Module, every time we call the Class/Method by using

Code: Select all

Globals.Script.<ScriptName>
?

Thanks and best regards,
Phong Duong

ajack
Posts: 44
Joined: Wed Feb 22, 2012 12:01 am

Re: TCP IP Communication between Beijer HMI and other Device

Post by ajack »

Hi all,

I already succeeded in implementing Sockets for Ethernet Transceiver. If anyone is interested can use attached file.

I do hope that anyone who faced same issues with me can save some time or even improve those codes.

Thanks,
Phong Duong

AMitchneck
Posts: 137
Joined: Mon Jun 11, 2012 2:10 pm

Re: TCP IP Communication between Beijer HMI and other Device

Post by AMitchneck »

Hi ajack,

1. Given the option, I typically use Asynchronous socket connections (as was in my sample script).

2. How acquainted are you with multi threading? What I typically use to drive a cyclic process is a System.Threading.Timer. Script modules have a "Created" event that fires during startup when the screen displays staring <script> which is where I put the initializer for the threading Timer (Proc_Timer = new Timer(Proc_Timer_Tick, null, 1000, 1000); // call timer function every second). This is more time-accurate than a form Timer, but can cause the Tick function to be called multiple times even if previous tick didn't complete. If this may be an issue, what I usually do is create a main processing thread with a loop that waits on an auto reset event that is set by the tick function.

3. That depends on how you declare the function. If you use public int test(), then you would need to call it through Globals.<scriptname>.test(), but if you declare it static than you don't need Globals.
Adam M.
Controls Engineer
FlexEnergy

Post Reply