W&T connects
Interfaces for TCP/IP, Ethernet, RS-232, RS-485, USB, 20mA, glass and plastic fiber optic cable, http, SNMP, OPC, Modbus TCP, I/O digital, I/O analog, ISA, PCI

Application for the Web-IO Digital:

Control and monitor the Web-IO Digital with Visual C#


Visual C++ was until recently one of the most widely used development platforms for creating Windows applications. But in the meantime, more and more programmers are working with the .Net Framework and creating their applications in C#.

Controlling Web-IO Digital with C Sharp

Using the following C# program example you can represent your Web-IO Digital with its inputs and outputs in a Windows application. You can also switch the Web-IO outputs.

You don’t have a Web-IO® yet but would like to try the example out sometime?

No problem: We will be glad to send you the Web-IO Digital 2xInput, 2xOutput at no charge for 30 days. Simply fill out a sample ordering form, and we will ship the Web-IO for testing on an open invoice. If you return the unit within 30 days, we will simply mark the invoice as paid.

To sample orders

Preparations

You have already provided your Web-IO Digital

1. Combine the various operating elements and display objects in the form

Form

2. Import resources and declarations from member variables

Firstly, all classes required for the network connection and the GUI are imported.


							using System;
							using System.Drawing;
							using System.Collections;
							using System.ComponentModel;
							using System.Windows.Forms;
							using System.Data;
							using System.Net;
							using System.Net.Sockets;
							using System.Text; 

Then the application components and important variables for a TCP connection are declared as member variables, thereby making them accessible to the class methods.

private System.Windows.Forms.CheckBox
				cb_Output0;
				private System.Windows.Forms.CheckBox
				cb_Output1;
				private System.Windows.Forms.CheckBox
				cb_Input0;
				private System.Windows.Forms.CheckBox
				cb_Input1;
				private System.Windows.Forms.CheckBox
				cb_Polling_Counter;
				private System.Windows.Forms.CheckBox
				cb_Polling_Outputs;
				private System.Windows.Forms.CheckBox
				cb_Polling_Inputs;
				private System.Windows.Forms.Button
				bt_Readall_Outputs;
				private System.Windows.Forms.Button
				bt_Readall_Inputs;
				private System.Windows.Forms.Button
				bt_Clear_Counter0;
				private System.Windows.Forms.Button
				bt_Clear_Counter1;
				private System.Windows.Forms.Button
				bt_Clearall_Counter;
				private System.Windows.Forms.Button
				bt_Read_Counter0;
				private System.Windows.Forms.Button
				bt_Read_Counter1;
				private System.Windows.Forms.Button
				bt_Readall_Counter;
				private System.Windows.Forms.Label
				lb_Counter0;
				private System.Windows.Forms.Label
				lb_Counter1;
				private System.Windows.Forms.Label
				lb_Intervall;
				private System.Windows.Forms.TextBox
				tb_Counter0;
				private System.Windows.Forms.TextBox
				tb_Counter1;
				private System.Windows.Forms.TextBox
				tb_Intervall;
				private System.Windows.Forms.Button
				bt_Connect;
				private System.Windows.Forms.Button
				bt_Disconnect;
				private System.Windows.Forms.TextBox
				tb_Password;
				private System.Windows.Forms.TextBox
				tb_Port;
				private System.Windows.Forms.TextBox
				tb_IP;
				private System.Windows.Forms.GroupBox
				gb_ioControlBox;
				private System.Windows.Forms.GroupBox
				gb_conControlBox;
				private System.Windows.Forms.StatusBar
				statusBar;
				private System.ComponentModel.Container
				components = null;
				private System.Windows.Forms.Timer
				counter;
				private System.Windows.Forms.Timer
				outputs;
				private System.Windows.Forms.Timer
				inputs;

				private Socket client;
				private string rcv;
				private int intervall;
				private byte[] buffer = new byte[256];

3. Starting the program

Setting up the operating elements

The group with the operating elements for the Web-IO is first blocked from operation. As soon as a connection is established, all elements are enabled which have a meaningful format.

The name of the respective operating element is derived from the element itself depending on the context. The first two characters in the name stand for the element type (cb -> Checkbox, bt -> Button, gb -> Groupbox and tb-> TextBox).

public mainWindow()
				{
					InitializeComponent();

					gb_ioControlBox.Enabled = false;
					bt_Disconnect.Enabled = false;
					cb_Input0.Enabled = false;
					cb_Input1.Enabled = false;
					tb_Counter0.Enabled = false;
					tb_Counter1.Enabled = false;
				} 

4. Connection control

Establishing the connection

After entering the IP address for the Web-IO in the text field tb_IP and Port 80 in the text field tb_port, clicking on the bt_connect button allows a connection to be opened. If no IP address or port is entered, a message is displayed in the status bar

Opening the connection

Now to be able to open a TCP connection, the already declared socket variable is initialized. It is given a stream and the connection type. In addition, a variable is generated which saves the port and IP address. So that the program can run asynchronous, it does not wait for events, but rather uses callback routines. Callback methods are initialized when a process is started and invoked when the corresponding event occurs, i.e. for example when a connection is opened, for sending or receiving.

private void bt_Connect_Click(object sender, System.EventArgs e)
				{
					try
					{
					if((tb_IP.Text != "") && (tb_Port.Text == "80"))
					{
						client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
						IPEndPoint ipep = new IPEndPoint(IPAddress.Parse(tb_IP.Text), int.Parse(tb_Port.Text));
						client.BeginConnect(ipep, new AsyncCallback(connectCallback), client);
					}
					else
						statusBar.Text = "IP and Port needed!";
					}
					catch(SocketException)
					{
					statusBar.Text = "Connection not possible!";
					}
				} 

In the following the callback routine is shown which is invoked when the connection is established. After successfully opening a connection, all useful operating elements for the application are enabled and the Connect button deactivated. In addition, the application immediately begins to go into receive ready mode. For this the callback routine "receiveCallback" is initialized, which is explained in greater detail below.

private void connectCallback(IAsyncResult ar)
				{
					try
					{
					client = (Socket) ar.AsyncState;
					client.EndConnect(ar);
					statusBar.Text = "Connected!";

					gb_ioControlBox.Enabled = true;
					bt_Disconnect.Enabled = true;
					bt_Connect.Enabled = false;

					intervall = 1000;
					client.BeginReceive(buffer, 0, 255, SocketFlags.None, new AsyncCallback(receiveCallback), client);
					}
					catch(Exception)
					{
					disconnect(); statusBar.Text = "Error while connecting!";
					}
				}
Disconnecting

The connection remains open until the user clicks on the Disconnect button or until it is ended by the Web-IO. After clicking on the button a message is displayed that the connection has been ended.

private void bt_Disconnect_Click(object
				sender, System.EventArgs e)
				{
					disconnect();
				}

When the connection is ended all elements must be returned to their initial state. It should then no longer be possible to actuate the Disconnect button.

private void disconnect()
				{
					try
					{
					client.Shutdown(SocketShutdown.Both);
					client.Close();
					statusBar.Text = "Disconnected!";

					gb_ioControlBox.Enabled = false;
					bt_Disconnect.Enabled = false;
					bt_Connect.Enabled = true;
					}
					catch(Exception)
					{
					statusBar.Text = "Not able to disconnect!";
					}
				} 

Now the connection is closed again and the application reset to its initial state.

5. Operation and communication from the client side

As soon as a connection is made with the Web-IO, the user can use the corresponding program elements to send commands to the Web-IO.

When sending a message to the Web-IO, a callback routine is invoked just as in the case of receiving.

private void sendCallback(IAsyncResult ar)
				{
					try
					{
					Socket tmp_client = (Socket) ar.AsyncState;
					int bytessend = tmp_client.EndSend(ar);
					}
					catch(Exception)
					{
					statusBar.Text = "Error while sending";
					}
				} 

Setting the outputs
The outputs on the Web-IO can be switched using the two checkboxes IDC_OUTPUT0 and IDC_OUTPUT1. The checkbox notes when it was clicked and then triggers an action. Depending on whether the checkbox is already set, the output is either set to ON or OFF.

private void cb_Output0_CheckedChanged(object sender, System.EventArgs e)
				{
					if(cb_Output0.Checked)
					send("GET /outputaccess0?PW=" + tb_Password.Text + "&State=ON&");
					else
					send("GET /outputaccess0?PW=" + tb_Password.Text + "&State=OFF&");
				}
private void cb_Output1_CheckedChanged(object sender, System.EventArgs e)
				{
					if(cb_Output1.Checked)
					send("GET /outputaccess1?PW=" + tb_Password.Text + "&State=ON&");
					else
					send("GET /outputaccess1?PW=" + tb_Password.Text + "&State=OFF&");
				}

Query output/input status

private void bt_Readall_Outputs_Click(object sender, System.EventArgs e)
				{
					send("GET /output?PW=" + tb_Password.Text + "&");
				}
private void bt_Readall_Inputs_Click(object sender, System.EventArgs e)
				{
					send("GET /input?PW=" + tb_Password.Text + "&");
				} 
Query counters

The following method sends a request to a particular counter and requests a reply containing the current state of the counter.

private void bt_Read_Counter0_Click(object sender, System.EventArgs e)
				{
					send("GET /counter0?PW=" + tb_Password.Text + "&");
				} 
private void bt_Read_Counter1_Click(object sender, System.EventArgs e)
				{
					send("GET /counter1?PW=" + tb_Password.Text + "&");
				} 

Of course all the counter states can also be polled using a single command.

private void bt_Readall_Counter_Click(object sender, System.EventArgs e)
				{
					send("GET /counter?PW=" + tb_Password.Text + "&");
				} 

Reset counters

private void bt_Clear_Counter0_Click(object sender, System.EventArgs e)
				{
					send("GET /counterclear0?PW=" + tb_Password.Text + "&");
				} 
private void bt_Clear_Counter1_Click(object sender, System.EventArgs e)
				{
					send("GET /counterclear1?PW=" + tb_Password.Text + "&");
				} 

Of course all the counters can be reset together using a single command.

private void bt_Clearall_Counter_Click(object sender, System.EventArgs e)
				{
					send("GET /counterclear?PW=" + tb_Password.Text + "&");
				} 

Since all counter states can be read or reset using one command, there must be a method implemented which processes the reply string from the Web-IO and assigns each counter in the application its specific state.

private void readAndClearCounter(string data)
				{
					int j = 0;
					string[] counter = new string[12];
					for(int i = 0; i < data.Length-1; i++)
					{
					if((data[i].CompareTo(';')) == 0)
						j++;
					else
						counter[j] += data[i].ToString();
					}
					tb_Counter0.Text = counter[0];
					tb_Counter1.Text = counter[1];
				} 

6. Data reception from the Web-IO

Process and display the received data
  • All commands and requests to the Web-IO are acknowledged with a reply string. The replies have a specific structure depending on the type:
  • For the outputs: output;<binary value of the output status in hexadecimal format>
  • For a special output: outputx;<ON or OFF>
  • For the inputs: input;<binary value of the input status in hexadecimal format>
  • For a special input inputx;<ON or OFF>
  • Then there is the reply string for a counter, which looks as follows.
  • Counter: counterx;<decimal counter state>
  • or counter;<decimal counter state 0 >; <decimal counter state 0 >; ... if you want to read all the counters at one time.
  • All reply strings are finished off with a 0 byte.

In our application the method receiveCallback() is invoked to receive such a message. In this method the reply string from the Web-IO is read and processed. The unique feature here is the event-driven invoking, which takes place as soon as the Web-IO sends data to the application.

private void receiveCallback(IAsyncResult ar)
				{
					int bytesRead;
				try
				{
					bytesRead = client.EndReceive(ar);
					rcv = string.Empty;
					rcv = Encoding.ASCII.GetString(buffer);

					client.BeginReceive(buffer, 0, 255, SocketFlags.None, new AsyncCallback(receiveCallback), client);
				}
				catch(Exception)
				{
					bytesRead = 0;
				}
				if(bytesRead == 0 && client.Connected)
					disconnect();
				else if(rcv != null)
				{
					if(rcv[0] == 'o')
					{
					int i = Int32.Parse(rcv.Substring(7), System.Globalization.NumberStyles.HexNumber);
					if((i & 1) == 1)
						cb_Output0.Checked = true;
					else
						cb_Output0.Checked = false;
					if((i & 2) == 2)
						cb_Output1.Checked = true;
					else
						cb_Output1.Checked = false;
					}
					if(rcv[0] == 'i')
					{
					int i = Int32.Parse(rcv.Substring(6), System.Globalization.NumberStyles.HexNumber);
					if((i & 1) == 1)
						cb_Input0.Checked = true;
					else
						cb_Input0.Checked = false;
					if((i & 2) == 2)
						cb_Input1.Checked = true;
					else
						cb_Input1.Checked = false;
					}
					if(rcv[0] == 'c')
					{
					if(rcv[7] == '0')
						tb_Counter0.Text = rcv.Substring(9);
					if(rcv[7] == '1')
						tb_Counter1.Text = rcv.Substring(9);
					if(rcv[7] == ';')
						readAndClearCounter(rcv.Substring(8));
					}
					}
				}

7. Polling

Cyclical polling of particular values

It is desirable that the status of an individual component be updated by the component itself, so that the application always shows the current status. For this the program uses a timer which sends cyclical queries to the Web-IO at a user-defined time interval.

The time interval can be specified in the field IDC_POLLINGTEXT.

Of course this also catches cases where the user enters a nonsense value, such as a negative time value.

private void tb_Intervall_TextChanged(object sender, System.EventArgs e)
				{
					try
					{
					if(Convert.ToInt32(tb_Intervall.Text) > 0)
					{
					intervall = Convert.ToInt32(tb_Intervall.Text);
					statusBar.Text = "New range: " + intervall.ToString() + " ms!";
					}
					else
					statusBar.Text = "Only positive Integer allowed!";
					}
					catch(Exception)
					{
					statusBar.Text = "Only positive Integer allowed!";
					}
				} 

To carry out cyclical polling of the Web-IO states, you can select from among polling the outputs, the inputs or the counters.

Each polling variant has its own timer initialized.

Actuating the checkbox cb_Polling_Outputs causes polling to be applied to the outputs. The corresponding timer is initialized.

private void cb_Polling_Outputs_CheckedChanged(object sender, System.EventArgs e)
				{
					if(cb_Polling_Outputs.Checked)
					{
					outputs = new System.Windows.Forms.Timer();
					outputs.Interval = intervall;
					outputs.Start();
					outputs.Tick += new EventHandler(timer_handler);
					}
					else
					outputs.Stop();
				} 

The same applies to inputs and counters

private void cb_Polling_Inputs_CheckedChanged(object sender, System.EventArgs e)
				{
					if(cb_Polling_Inputs.Checked)
					{
					inputs = new System.Windows.Forms.Timer();
					inputs.Interval = intervall;
					inputs.Start();
					inputs.Tick += new EventHandler(timer_handler);
					}
					else
					inputs.Stop();
				} 
private void cb_Polling_Counter_CheckedChanged(object sender, System.EventArgs e)
				{
					if(cb_Polling_Counter.Checked)
					{
					counter = new System.Windows.Forms.Timer();
					counter.Interval = intervall;
					counter.Start();
					counter.Tick += new EventHandler(timer_handler);
					}
					else
					counter.Stop();
				} 

In this method the respective event of the timer which has just reported is captured and assigned to a certain action.

 private void timer_handler(object sender, System.EventArgs e)
				{
					if(sender == counter) bt_Readall_Counter_Click(sender, e);
					if(sender == outputs) bt_Readall_Outputs_Click(sender, e);
					if(sender == inputs)  bt_Readall_Inputs_Click (sender, e);
				} 

The sample program supports all common functions of the Web-IO in command string mode, optimized for the Web-IO 2x Digital Input, 2x Digital Output. For the other Web-IO models you may have to adapt the program. Additional program examples for socket programming can be found on the tool pages for the Web-IO. A detailed description for the socket interface of the Web-IO Digital models can be found in the reference manual.

Download program example

You don’t have a Web-IO® yet but would like to try the example out sometime?

No problem: We will be glad to send you the Web-IO Digital 2xInput, 2xOutput at no charge for 30 days. Simply fill out a sample ordering form, and we will ship the Web-IO for testing on an open invoice. If you return the unit within 30 days, we will simply mark the invoice as paid.

To sample orders