Beckhoff Information System - German

TwinCAT ADS Web Service: Samples

TwinCAT ADS Web Service: Samples

Sample | Download link
Implementation Consumer in C# | Sample01.exe
Implementation Consumer in C++ | WebServiceSampleCPP.zip
Implementation Consumer in Java | WebServiceSampleJava.zip
Implementation ASP.NET 2.0 AJAX "Atlas" | PLC Sample ASP.NET 2.0 AJAX - C# Sample 01 ASP.NET 2.0 AJAX - C# Sample 02
Implementation Consumer in Delphi 8 for .NET | Sample01.exe


TwinCAT ADS Web Service: C#-Sample

TwinCAT ADS Web Service: C# example

Consumer in C# to read and write PLC variables

This sample explains how to create an ADS-WebService-Consumer to read and write PLC-Variables via ADS-HTTP.

Creating a WebService-Consumers within the Microsoft VisualStudio.NET

In Visual Studio select "New Project" and create a new C# - Windows Application.

  • By selecting the template "Windows-Application" the new application is only running on .NET-platforms.
  • By selecting the template "Smart Device Application" the new application is running on .NET-platforms and on .NET-CompactFramework (CE-) platforms.
    By selecting the .NET-CompactFramework (CE-) platform restrictions may occure.

After creating the projects go to "Projects" "Add Web Reference...".

In the following dialog you may insert the URL of the WebService-WSDL-file or you can browse for it by clicking on "Web services on the local machine".

Name the reference and click the button "Add Reference" to complete .

To catch SOAP-Exceptions add the following line to the first lines of the source-code:

using System.Web.Services.Protocols;

To create a WebService-object insert the following line after "public class NameOfYourForm: System.Windows.Forms.Form":

TcAdsWebService.TcAdsWebService TcWebService = new TcAdsWebService.TcAdsWebService();

Add the following line in the constructor ("public NameOfYourForm") after "InitializeComponent();":

TcWebService.Url = "http://localhost/TcAdsWebService/TcAdsWebService.dll";

// Sample 1 :
TcWebService.Url = "http://192.168.0.2/TcAdsWebService/TcAdsWebService.dll";

// Sample 2 :
TcWebService.Url = "http://CX_xxxxxx/TcAdsWebService/TcAdsWebService.dll";

The address must be the URL of your TwinCAT ADS WebService-DLL-file .

Converting variables to byte-arrays

Variables have to be converted to byte-arrays if they should be used with the ADS-WebService. Therefore it is necessary to be able to convert variables to byte-arrays and vice versa:

This could be realized with the BitConverter-class:

byte[] abDataBool = new byte[1];
abDataBool = BitConverter.GetBytes(bValueBool);

byte[] abDataInt = new byte[2];
abDataInt = BitConverter.GetBytes((Int16)iValueInt)

In this example a "bool"- and an "int"-variable were converted to byte-arrays.

To convert a byte-array back to a variable use the BitConverter-class as followed:

byte[] abDataBuffer = new byte[3];
bool bVarBool = BitConverter.ToBoolean(abDataBuffer,0);
int iVarInt = BitConverter.ToInt16(abDataBuffer,1);

Strings are converted with the the "ASCII-Encoder":

string szValueString;
byte[] abDataString = new byte[81];
System.Text.ASCIIEncoding encoder = new System.Text.ASCIIEncoding();
encoder.GetBytes(szValueString, 0, encoder.GetByteCount(szValueString), abDataString, 0);

To convert a byte-array back to a string use the following code:

byte[] abDataBuffer = new byte[81];
System.Text.ASCIIEncoding encoder = new System.Text.ASCIIEncoding();
string VarString = encoder.GetString(abDataBuffer, 3, 81);

You can get more detailed information about this methods and classes in literature for C#-Application-Developement.

Reading PLC-variables

To read a PLC-Variable use the "read"-method of the WebService-object:

WebService.Read(string netId, int nPort, System.UInt32 indexGroup, System.UInt32 indexOffset, int cblen, out System.Byte[] ppData);

  • string netId: String indicating the AMS-Net-Id of the PLC
  • int nPort: Port-number of the Runtime-System
  • System.UInt32 indexGroup: IndexGroup of the variables to read
  • System.UInt32 indexOffset: First byte to read
  • int cblen: Number of bytes to read
  • out System.Byte[] ppData: Byte-array to save the PLC-data into

Example:

try
{
    TcWebService.Read("192.168.0.2.1.1", 801, 0x4020, 0, 84, out abDataBuffer);
}
catch (SoapException ex)
{
    MessageBox.Show(ex.Message);
}
catch (Exception ex)
{
    MessageBox.Show(ex.Message);
}

Writing PLC-variables

To write a PLC-Variable use the "write"-method of the WebService-object:

WebService.Write(string netId, int nPort, System.UInt32 indexGroup, System.UInt32 indexOffset, System.Byte[] pData);

  • string netId: String indicating the AMS-Net-Id of the PLC
  • int nPort: Port-number of the Runtime-System
  • System.UInt32 indexGroup: IndexGroup of the variable
  • System.UInt32 indexOffset: First byte to write to
  • System.Byte[] pData: Byte-array containing the data to write

Example:

byte[] Data = new byte[10];

try
{
    TcWebService.Write("192.168.0.2.1.1", 801, 0x4020, 0, Data);
}
catch (SoapException ex)
{
    MessageBox.Show(ex.Message);
}
catch (Exception ex)
{
    MessageBox.Show(ex.Message);
}

Sample-Application:

PLC-program, IEC1131 declaration of the variables

PROGRAM MAIN
VAR
PlcVarBool AT %MX0.0 : BOOL := TRUE;
PlcVarInt AT %MW1 : INT := 1234;
PlcVarString AT %MD3 : STRING := 'Hello Automation';
END_VAR

C#-Application, the layout :

The source-code:

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Web.Services.Protocols;	// Catches the SoapExceptions

namespace WebServiceTestConsumer
{
    public class frmWebServiceTestConsumer : System.Windows.Forms.Form
    {
        private System.ComponentModel.Container components = null;

        #region forms
        private System.Windows.Forms.Label lblBool;
        private System.Windows.Forms.Label lblInt;
        private System.Windows.Forms.Label lblString;
        private System.Windows.Forms.TextBox txtBool;
        private System.Windows.Forms.TextBox txtInt;
        private System.Windows.Forms.TextBox txtString;
        private System.Windows.Forms.Button btnRead;
        private System.Windows.Forms.Button btnWrite;
        #endregion

        #region variables and instances

        // Encodes byte-array to Strings and vice versa
        private	System.Text.ASCIIEncoding		encoder			=	new	System.Text.ASCIIEncoding();

        // Instance of the TcAdsWebService
        private	TcAdsWebService.TcAdsWebService	TcWebService	=	new	TcAdsWebService.TcAdsWebService();

        private	string	szWebServiceUrl		= "http://192.168.0.2/TcAdsWebService/TcAdsWebService.dll";
        public	string	szAmsNetId			=	"192.168.0.2.1.1";
        public	int		iPort			=	801;
        public	UInt32	iIndexGroup			=	0x4020;

        #endregion

        public frmWebServiceTestConsumer()
        {
            //
            // Required for Windows Form Designer support
            //
            InitializeComponent();

            // Links the WebService with its library
            TcWebService.Url = szWebServiceUrl;
        }

        protected override void Dispose( bool disposing )
        {
            if( disposing )
            {
                if (components != null)
                {
                    components.Dispose();
                }
            }
            base.Dispose( disposing );
        }

        #region Windows Form Designer generated code
        private void InitializeComponent()
        {
            this.lblBool = new System.Windows.Forms.Label();
            this.lblInt = new System.Windows.Forms.Label();
            this.lblString = new System.Windows.Forms.Label();
            this.txtBool = new System.Windows.Forms.TextBox();
            this.txtInt = new System.Windows.Forms.TextBox();
            this.txtString = new System.Windows.Forms.TextBox();
            this.btnRead = new System.Windows.Forms.Button();
            this.btnWrite = new System.Windows.Forms.Button();
            this.SuspendLayout();
            //
            // lblBool
            //
            this.lblBool.Location = new System.Drawing.Point(40, 24);
            this.lblBool.Name = "lblBool";
            this.lblBool.TabIndex = 0;
            this.lblBool.Text = "VarBool:";
            //
            // lblInt
            //
            this.lblInt.Location = new System.Drawing.Point(40, 80);
            this.lblInt.Name = "lblInt";
            this.lblInt.TabIndex = 1;
            this.lblInt.Text = "VarInt:";
            //
            // lblString
            //
            this.lblString.Location = new System.Drawing.Point(40, 136);
            this.lblString.Name = "lblString";
            this.lblString.TabIndex = 2;
            this.lblString.Text = "VarString:";
            //
            // txtBool
            //
            this.txtBool.Location = new System.Drawing.Point(152, 24);
            this.txtBool.Name = "txtBool";
            this.txtBool.TabIndex = 3;
            this.txtBool.Text = "";
            //
            // txtInt
            //
            this.txtInt.Location = new System.Drawing.Point(152, 80);
            this.txtInt.Name = "txtInt";
            this.txtInt.TabIndex = 4;
            this.txtInt.Text = "";
            //
            // txtString
            //
            this.txtString.Location = new System.Drawing.Point(152, 136);
            this.txtString.Name = "txtString";
            this.txtString.TabIndex = 5;
            this.txtString.Text = "";
            //
            // btnRead
            //
            this.btnRead.FlatStyle = System.Windows.Forms.FlatStyle.System;
            this.btnRead.Location = new System.Drawing.Point(48, 216);
            this.btnRead.Name = "btnRead";
            this.btnRead.TabIndex = 6;
            this.btnRead.Text = "&Read";
            this.btnRead.Click += new System.EventHandler(this.btnRead_Click);
            //
            // btnWrite
            //
            this.btnWrite.FlatStyle = System.Windows.Forms.FlatStyle.System;
            this.btnWrite.Location = new System.Drawing.Point(168, 216);
            this.btnWrite.Name = "btnWrite";
            this.btnWrite.TabIndex = 7;
            this.btnWrite.Text = "&Write";
            this.btnWrite.Click += new System.EventHandler(this.btnWrite_Click);
            //
            // frmWebServiceTestConsumer
            //
            this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
            this.ClientSize = new System.Drawing.Size(292, 266);
            this.Controls.Add(this.lblBool);
            this.Controls.Add(this.lblInt);
            this.Controls.Add(this.lblString);
            this.Controls.Add(this.txtBool);
            this.Controls.Add(this.txtInt);
            this.Controls.Add(this.txtString);
            this.Controls.Add(this.btnRead);
            this.Controls.Add(this.btnWrite);
            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.Fixed3D;
            this.MaximizeBox = false;
            this.MinimizeBox = false;
            this.Name = "frmWebServiceTestConsumer";
            this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
            this.Text = "WebServiceTestConsumer";
            this.ResumeLayout(false);

        }
        #endregion

        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.Run(new frmWebServiceTestConsumer());
        }

        #region Event-Methods

        private void btnRead_Click(object sender, System.EventArgs e)
        {
            Read();
        }

        private void btnWrite_Click(object sender, System.EventArgs e)
        {
            Write();
        }

        #endregion

        #region Worker-Methods

        private void Read()
        {
            // DataBuffer for the incoming data
            byte[] abDataBuffer = new byte[84]; //1 byte for "PlcVarBool", 2 bytes for "PlcVarInt" and 81 bytes for "PlcVarString" = 84 bytes

            try
            {
                TcWebService.Read(	szAmsNetId, iPort, iIndexGroup, 0, 84, out abDataBuffer);

                // Converts the first byte of the buffer to bool
                bool bVarBool		=	BitConverter.ToBoolean(abDataBuffer, 0);

                // Converts the second and third byte of the buffer to int
                int iVarInt			=	BitConverter.ToInt16(abDataBuffer, 1);

                // Converts the other bytes of the buffer to string
                string szVarString	=	encoder.GetString(abDataBuffer, 3, 81);

                // Writes values into the text-boxes
                txtBool.Text = bVarBool.ToString();
                txtInt.Text = iVarInt.ToString();
                txtString.Text = szVarString;
            }
            catch (SoapException ex)
            {
                MessageBox.Show(ex.Message);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void Write()
        {
            try
            {
                // byte-arrays for the variables
                byte[]	abDataBool		=	new	byte[1];
                byte[]	abDataInt		=	new	byte[2];
                byte[]	abDataString	=	new	byte[81];

                // Gets values for the text-boxes
                bool	bValueBool		=	Convert.ToBoolean(txtBool.Text);
                int		iValueInt		=	Convert.ToInt16(txtInt.Text);
                string	szValueString	=	txtString.Text;

                // Converting variables to byte-arrays
                abDataBool	=	BitConverter.GetBytes(bValueBool);
                abDataInt	=	BitConverter.GetBytes((Int16)iValueInt);

                encoder.GetBytes(	szValueString,							// Source
                                    0,										// Position of the first character to convert
                                    encoder.GetByteCount(szValueString),	// Gets the length of the source
                                    abDataString,							// Byte-array to save the conversion to
                                    0);										// First byte in the array to save the conversion to

                // Writing values to PLC
                TcWebService.Write(szAmsNetId, iPort, iIndexGroup, 0, abDataBool);
                TcWebService.Write(szAmsNetId, iPort, iIndexGroup, 1, abDataInt);
                TcWebService.Write(szAmsNetId, iPort, iIndexGroup, 3, abDataString);
            }
            catch (SoapException ex)
            {
                MessageBox.Show(ex.Message);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        #endregion
    }
}

Language / IDE | Extract the sample program
Visual C# | Sample01.exe


TwinCAT ADS Web Service: C++-Sample

TwinCAT ADS Web Service: C++ example

Consumer in C++ to read and write PLC variables

To configurate the ADS Webservice for the Internet Information Servers (IIS) please check the installation note.

This sample explains how to create an ADS-WebService-Consumer to read and write PLC-Variables via ADS-HTTP.

Unzip the sample 'WebServiceTestConsumer (C++)'.

Creating a WebService-Consumers within the Microsoft Visual C++

Create a new project with the help of the MFC-AppWizard.
Copy th files 'WebServiceConnector.cpp', 'WebServiceConnector.h', 'Base64.cpp' and 'Base64.h' (can be found in the 'WebServiceSampleCPP.zip'-file) to your project-folder and add them into the project
Insert the following line to the file in which you want to use the ADS Web Service:

#include "WebServiceConnector.h"

Before you can read and write you have to create an object of the WebServiceConnector and connect to the WebService:

CWebServiceConnector webServiceConnector;

webServiceConnector.Connect("http://192.168.0.2.1.1/TcAdsWebService/TcAdsWebService.dll");
The address must be the URL of your TwinCAT ADS WebService-DLL-file .

Reading PLC -variables

To read a PLC-variable use the "Read"-method of the WebServiceConnector-object:

HRESULT Read(char* netId, int port, ULONG indexGroup, ULONG indexOffset, ULONG* pcbData, BYTE* pData);

  • char* netId: String indicating the AMS-Net-Id of the PLC
  • int port: Port-number of the Runtime-System
  • ULONG indexGroup: IndexGroup of the variables to read
  • ULONG indexOffset: First byte to read
  • ULONG cblen: Number of bytes to read
  • Byte[] pData: Byte-array to save the PLC-data into
  • return value: errorcode

The 3 methods

HRESULT ReadInt (char* netId, int port, ULONG indexGroup, ULONG indexOffset, ULONG cblen, int& ret);
HRESULT ReadBool (char* netId, int port, ULONG indexGroup, ULONG indexOffset, ULONG cblen, bool& ret);
HRESULT ReadString (char* netId, int port, ULONG indexGroup, ULONG indexOffset, ULONG cblen, CString& ret);

convert the variables to their corresponding type.

Example:

bool Boolean;
if (webServiceConnector.ReadBool("192.168.0.2.1.1", 801, 16416, 0, 1, Boolean)!=S_OK)
            MessageBox("Error");

Writing PLC-variables

HRESULT Write(char* netId, int port, ULONG indexGroup, ULONG indexOffset, ULONG cblen, BYTE* pData);

  • netId: String indicating the AMS-Net-Id of the PLC
  • port: Port-number of the Runtime-System
  • indexGroup: IndexGroup of the variable
  • indexOffset: First byte to write to
  • pData: Byte-array containing the data to write
  • return value: errorcode

The 3 methods

HRESULT WriteInt(char* netId, int port, ULONG indexGroup, ULONG indexOffset, ULONG cblen, int Value);
HRESULT WriteBool(char* netId, int port, ULONG indexGroup, ULONG indexOffset, ULONG cblen, bool Value);
HRESULT WriteString(char* netId, int port, ULONG indexGroup, ULONG indexOffset, ULONG cblen, CString Value);

convert the variables to a byte-arrays.

Example:

if (webServiceConnector.WriteBool("192.168.0.2.1.1", 801, 16416, 0, 1, true)!=S_OK)
            MessageBox("Error");

Errorcodes

S_OK - No error
E_NO_CON - No connetion to the WebService
E_SEND - Unable to send data to the WebService
E_RESPONSE - Unknown response from the WebService
E_FAILED - Unknown error

Sample application :

PLC-program, IEC1131 daclaration of the variables:

PROGRAM MAIN
VAR
    PlcVarBool    AT %MX0.0  : BOOL := TRUE;
    PlcVarInt         AT %MW1    : INT := 1234;
    PlcVarString  AT %MD3    : STRING := 'Hello Automation';
END_VAR

C++ Application, the layout:

The source-code:

void CWebServiceTestConsumerDlg::OnRead()
{
    CWebServiceConnector webServiceConnector;
    webServiceConnector.Connect(WebServiceURL);
    if (webServiceConnector.IsConnected())
    {
        int Integer;
        bool Boolean;
        CString String;

        int port = 801;
        int group = 16416;
        unsigned long size;
        int offset;

        /* read bool */
        size = 1;
        offset = 0;
        if (webServiceConnector.ReadBool(WebServiceNetId,port,group,offset,size,Boolean) == S_OK)
        {
            m_boolean = Boolean;
        }
        else
        {
            MessageBox("Error");
            return;
        }

        /* read int */
        size = 2;
        offset = 1;
        if (webServiceConnector.ReadInt(WebServiceNetId,port,group,offset,size,Integer) == S_OK)
        {
            m_integer = Integer;
        }
        else
        {
            MessageBox("Error");
            return;
        }

        /* read string */
        size = 81;
        offset = 3;
        if (webServiceConnector.ReadString(WebServiceNetId,port,group,offset,size,String) == S_OK)
        {
            m_string = String;
        }
        else
        {
            MessageBox("Error");
            return;
        }
        UpdateData(false);
    }
    else MessageBox("Error");
}

void CWebServiceTestConsumerDlg::OnWrite()
{
    CWebServiceConnector webServiceConnector;
    webServiceConnector.Connect(WebServiceURL);
    if (webServiceConnector.IsConnected())
    {
        UpdateData(true);

        int port = 801;
        int group = 16416;
        int offset;
        unsigned long size;

        /* write boolean */
        size = 1;
        offset = 0;
        bool boolean = false;
        if (m_boolean==1)
            boolean = true;
        if (webServiceConnector.WriteBool(WebServiceNetId,port,group,offset,size,boolean)!=S_OK)
            MessageBox("Error");

        /* write integer */
        size = 2;
        offset = 1;

        if (webServiceConnector.WriteInt(WebServiceNetId,port,group,offset,size,m_integer)!=S_OK)
            MessageBox("Error");

        /* write string */
        size = 81;
        offset = 3;

        if (webServiceConnector.WriteString(WebServiceNetId,port,group,offset,size,m_string)!=S_OK)
            MessageBox("Error");
    }
    else MessageBox("Error");
}

Complete sourcecode


TwinCAT ADS Web Service: Java-Sample

TwinCAT ADS Web Service: Java example

Consumer in Java to read and write PLC variables

This sample explains how to create an ADS-WebService-Consumer to read and write PLC-Variables via ADS-HTTP.

Unzip the sample 'WebServiceTestConsumer (Java)'.

Copy the files "TcAdsSOAP.java" and "Base64.java" to the folder of your Java-application and compile them.
Add the following line to the Java-file in which you want to use the ADS WebService:

TcAdsSOAP tcSoap = new TcAdsSOAP("http://192.168.0.2/TcAdsWebService/TcAdsWebService.dll");

The address must be the URL of your TwinCAT ADS WebService-DLL-file .

reading PLC-variables

To read PLC-variables use the following method of the TcAdsSoap-object:

DataInputStream SOAPCall(String netId, int port, long group, long offset, int cblen)

  • String netId: String indicating the AMS-Net-Id of the PLC
  • int port: Port-number of the Runtime-System
  • long indexGroup: IndexGroup of the variables to read
  • long indexOffset: First byte to read
  • int cblen: Number of bytes to read
  • return value: DataInputStream with the read data, throws exception on failure

The 3 methods

short ReadInt(String netId, int port, long group, long offset)
boolean ReadBool(String netId, int port, long group, long offset)
String ReadString(String netId, int port, long group, long offset, int cblen)

convert the variables to their corresponding type.

Example:

boolean Bool1;
try
{
    Bool1 = tcSoap.ReadBool("192.168.0.2.1.1", 801, 16416, 0)
}
catch (Exception e)
{
    System.out.println("Error");
}

Write PLC-variables

boolean SOAPWrite(String netId, int port, long group, long offset, byte[] data)

  • String netId: String indicating the AMS-Net-Id of the PLC
  • int port: Port-number of the Runtime-System
  • long indexGroup: IndexGroup of the variable
  • long indexOffset: First byte to write to
  • byte[] pData: Byte-array containing the data to write
  • return value: "true" if successful, throws exception on failure

the 3 methods

boolean WriteBool(String netId, int port, long group, long offset, boolean data)
boolean WriteInt(String netId, int port, long group, long offset, int data)
boolean WriteString(String netId, int port, long group, long offset, String data)

convert the variables to a byte-arrays.

Example:

try
{
    tcSoap.WriteBool("192.168.0.2.1.1", 801, 16416, true)
}
catch (Exception e)
{
    System.out.println("Error");
}

Sample application:

PLC-program, IEC1131 daclaration of the variables:

PROGRAM MAIN
VAR
    PlcVarBool    AT %MX0.0  : BOOL := TRUE;
    PlcVarInt     AT %MW1    : INT := 1234;
    PlcVarString  AT %MD3    : STRING := 'Hello Automation';
END_VAR

The source-code:

public class AdSWebServiceSample
{
    public static void main(String args[])
    {
        TcAdsSOAP tcSoap = new TcAdsSOAP("http://192.168.0.2/TcAdsWebService/TcAdsWebService.dll");
        try
        {
            String netId = "192.168.0.2.1.1";
            int port = 801;
            int offset = 16416;
            /* write bool */
            boolean testBool = true;
            if (tcSoap.WriteBool(netId,port,offset,0,testBool))
                System.out.println("Boolean "+testBool+" Written");

            /* write int */
            int testInt = 1234;
            if (tcSoap.WriteInt(netId,port,offset,1,testInt))
                System.out.println("Integer "+testInt+" Written");

            /* write string */
            String testString = "Hello Automation";
            if (tcSoap.WriteString(netId,port,offset,3,testString))
                System.out.println("String "+testString+" Written");

            /* read bool */
            System.out.println(String.valueOf(tcSoap.ReadBool(netId,port,offset,0) ));

            /* read int */
            System.out.println(String.valueOf(tcSoap.ReadInt(netId,port,offset,1) ));

            /* read string */
            System.out.println(tcSoap.ReadString(netId,port,offset,3,81));

        }
        catch(Exception ex)
        {
            System.out.println(String.valueOf(ex));
        }
    }
}

Complete sourcecode


TwinCAT ADS Web Service: ASP.NET 2.0 AJAX Extensions Sample

TwinCAT ADS Web Service: ASP.NET 2.0 AJAX example

ASP.NET 2.0 AJAX

Microsoft ASP.NET 2.0 AJAX Extensions is the new name for the ASP.NET technology code-named "Atlas".

System Requirements

  • Supported Operating Systems: Windows Server 2003; Windows Vista; Windows XP
  • Required Software:
    • Microsoft .NET Framework Version 2.0
      Link: http://msdn.microsoft.com/netframework/downloads/updates/default.aspx
    • Microsoft Internet Explorer 5.01 (or later)
    • Visual Studio 2005
    • Framework "ASP.NET 2.0 AJAX Extensions" (free)
      Link : http://ajax.asp.net/
    • Download - Microsoft ASP.NET AJAX

Get Started with ASP.NET 2.0 AJAX in VS2005?

Step 1. Create a new project

Open Visual Studio 2005, choose under File , New the pption Website... Now you create a new website.
Choose under the "Templates" the "ASP.NET AJAX-Enabled Web Site" template.
Choose the sourcecode language: Visual C#

Create a new 'ASP.NET AJAX-Enabled Web Site'

Step 2. Add the reference:

Add the reference of TwinCAT.Ads.dll to VS2005 -> Menu -> Website -> Add Reference....
The default installation path for .NET Framework 2.0 of TwinCAT.Ads.dll is C:\TwinCAT\ADS Api\.NET\v2.0.50727\TwinCAT.ADS.dll
Please work with the latest greatest Version.

Add the Reference 'TwinCAT.Ads.dll'

Step 3. Add AJAX component:

Add the Timer and the UpdatePanel of AJAX Extensions to the web file "Default.aspx" from Toolbox of Visual Studio 2005.

Add AJAX Extensions

4. Edit properties:

Change Interval of the Timer1:
Interval = "3000"

Change the option UpdateMode of the UpdatePanel1:
UpdateMode = "Conditional"

5. Read PLC variables:

Use the TcAdsClient.Read() to read the variables from ADS device. Reads data synchronously from an ADS device and writes it to the given stream.
TcAdsClient.Read(int indexGroup, int indexOffset, AdsStream dataStream, int offset, int length);

Parameters:

  • indexGroup: - Contains the index group number of the requested ADS service.
  • indexOffset: - Contains the index offset number of the requested ADS service.
  • dataStream: - Stream that receives the data.
  • offset: - Offset of the data in dataStream.
  • length: - Length of the data in dataStream.

Step 6. ASP.NET 2.0 AJAX Sample 01

Default.aspx:

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>ASP.NET 2.0 AJAX Sample 01</title>
</head>
<body>
    <form id="form1" method="post" runat="server">
        <div>
            <asp:ScriptManager ID="ScriptManager1" runat="server" />
            <asp:Timer ID="Timer1" runat="server" Interval="3000" OnTick="Timer1_Tick">
            </asp:Timer>

            <!-- ASP.NET AJAX UpdatePanel1 - Only the panel contet is updated. -->
            <asp:UpdatePanel ID="UpdatePanel1" runat="server" UpdateMode="Conditional">
                <ContentTemplate>

                    UpdatePanel content refreshed at <%=DateTime.Now.ToString() %>

                    <asp:Label ID="lblPlcVarBool01" runat="server" Text="PlcVarBool:"
                    Style="z-index: 101; left: 10px; position: absolute; top: 50px"></asp:Label>
                    <asp:Label ID="lblPlcVarBool02" runat="server" Text="-" BackColor="Black" ForeColor="White"
                    Style="z-index: 101; left: 100px; position: absolute; top: 50px"></asp:Label>

                    <asp:Label ID="lblPlcVarInt01" runat="server" Text="PlcVarInt:"
                    Style="z-index: 101; left: 10px; position: absolute; top: 100px"></asp:Label>
                    <asp:Label ID="lblPlcVarInt02" runat="server" Text="-" BackColor="Black" ForeColor="White"
                    Style="z-index: 101; left: 100px; position: absolute; top: 100px"></asp:Label>

                    <asp:Label ID="lblMessage01" runat="server" Text="Message:"
                    Style="z-index: 101; left: 10px; position: absolute; top: 200px"></asp:Label>
                    <asp:Label ID="lblMessage02" runat="server" Text="-"
                    Style="z-index: 101; left: 100px; position: absolute; top: 200px"></asp:Label>

                    <asp:Button ID="btnRefreshAll" runat="server" Text="Refresh All" Width="160px" OnClick="btnRefreshAll_Click"
                    Style="z-index: 201; left: 207px; position: absolute; top: 250px"/>

                    <asp:Label ID="lblPlcVarString01" runat="server" Text="PlcVarString:"
                    Style="z-index: 101; left: 10px; position: absolute; top: 150px"></asp:Label>
                    <asp:Label ID="lblPlcVarString02" runat="server" Text="-" BackColor="Black" ForeColor="White"
                    Style="z-index: 101; left: 100px; position: absolute; top: 150px"></asp:Label>

                </ContentTemplate>
                <Triggers>
                    <asp:AsyncPostBackTrigger ControlID="Timer1" />
                </Triggers>
            </asp:UpdatePanel>
        </div>
    </form>
</body>
</html>

Default.aspx.cs

NOTE : You must change the AMS NET ID and AdsServerPort to your local project settings

using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Drawing;
using TwinCAT.Ads;
using System.IO;

public partial class _Default : System.Web.UI.Page
{
    // ADS Kommunication with ADS device
    TcAdsClient tcAds = new TcAdsClient();

    // AMS NET ID <- Change this AMS NET ID for your TwinCAT Configuration
    string strAmsNetId = "192.168.0.2.1.1";

    // AMS Port (801, 811, 821, 831) <- Change this AMS Port for your TwinCAT Configuration
    int iAdsServerPort = 801;

    protected void Page_Load(object sender, EventArgs e)
    {

    }

    public void RemoteStatusRead()
    {
        try
        {
            tcAds.Connect(strAmsNetId, iAdsServerPort);
            tcAds.Timeout = 200;

            AdsStream dataStream = new AdsStream(171);
            BinaryReader binRead = new BinaryReader(dataStream);

            // read bool variable with IndexGroup and IndexOffset
            tcAds.Read(16417, 0, dataStream, 0, 1);
            // read int variable with IndexGroup and IndexOffset
            tcAds.Read(16416, 1, dataStream, 1, 2);
            // read string variable with IndexGroup and IndexOffset
            tcAds.Read(16416, 5, dataStream, 3, 168);

            bool bVarBool = false;
            byte b = binRead.ReadByte();
            if (b == 0) bVarBool = false;
            else bVarBool = true;

            if (bVarBool == true)
            {
                lblPlcVarBool02.Text = "TRUE";
                lblPlcVarBool02.BackColor = Color.Blue;
                lblPlcVarBool02.ForeColor = Color.White;
            }
            else
            {
                lblPlcVarBool02.Text = "FALSE";
                lblPlcVarBool02.BackColor = Color.Black;
                lblPlcVarBool02.ForeColor = Color.White;
            }

            int iData = 0;
            iData = binRead.ReadByte();

            if (iData != 0)
            {
                lblPlcVarInt02.Text = iData.ToString();
            }
            else
            {
                lblPlcVarInt02.Text = "-";
            }

            char [] strData = new char[160];
            strData = binRead.ReadChars(160);

            if (strData != null)
            {
                lblPlcVarString02.Text = "";
                for (int i = 1; i < 160; i++)
                {
                    lblPlcVarString02.Text += strData[i];
                }
            }
            else
            {
                lblPlcVarString02.Text = "-";
            }
            lblMessage02.Text = "";
        }
        catch(Exception ex)
        {
            lblMessage02.Text = ex.Message;
        }
    }

   protected void btnRefreshAll_Click(object sender, EventArgs e)
    {
        RemoteStatusRead();

        // update content of the UpdatePanel1
        UpdatePanel1.Update();
    }

    protected void Timer1_Tick(object sender, EventArgs e)
    {
        RemoteStatusRead();

        // update content of the UpdatePanel1
        UpdatePanel1.Update();
    }
}

Step 7. PLC Sample

PROGRAM MAIN
VAR
    PlcVarBool    AT %MX0.0  : BOOL := TRUE;
    PlcVarInt     AT %MW1    : INT := 0;
    PlcVarIntMax  AT %MW3    : INT := 1000;
    PlcVarString  AT %MD5    : STRING(20);
    TON1: TON;
    bool1: BOOL;
    time1: TIME;
END_VAR

PlcVarInt := PlcVarInt + 1;
IF PlcVarInt > PlcVarIntMax THEN
    PlcVarInt := 0;
    PlcVarBool := NOT PlcVarBool;
END_IF

TON1(IN:=TRUE , PT:=t#5m , Q=>bool1 , ET=>time1 );
IF bool1 THEN
TON1(IN:=FALSE , PT:= , Q=> , ET=> );
END_IF

PlcVarString := TIME_TO_STRING(time1);

Step 8. Download samples

PLC sample
ASP.NET 2.0 AJAX - C# sample 01
ASP.NET 2.0 AJAX - C# sample 02

Step 9. Configuration of the Microsoft Internet Information Services (IIS)

Open the IIS:

  • Start -> Control Panel -> Administrative Tools -> Internet Information Services
  • Add a new virtual Directory for a new website: IIS -> (local computer) -> Web Sites -> Default Web Sites -> New -> Virtual Directory...

Settings for IIS:
  • Alias: AjaxSample01
  • Directory: C:\Projects\WebSites\AJAXEnabledWebSite1
  • Access Permisions: Choose "Read", "Run scripts" and "Execute"
  • Important: Click to Node "AjaxSample01" and change the IIS Properties "ASP.NET" of the Web site to Version 2.0

Step 10. Demo of the AJAX Website Sample Microsoft IE

AJAX Website with Internet Explorer 7

And browse to the web site with the "Default.aspx" in IIS
or open the link http://localhost/AjaxSample01/Default.aspx with Internet Explorer.
(p.E. http://192.168.0.2/AjaxSample01/Default.aspx or http://<ip-of-PC>/AjaxSample01/Default.aspx )

Note: This example can be used only with access by a user with an instance.


Delphi ADS Web Service: Delphi 8 .NET example

TwinCAT ADS Web Service: Delphi example

Consumer in Delphi 8 for .NET to read and write PLC variables

The example explains how to create an ADS-Web Service consumer for reading and writing PLC variables via ADS-HTTP.

Requirements:

  • Delphi 8 for Microsoft .NET framework;
  • Web service consumer for Windows XP platform (Windows Forms .NET application);
  • Web service server was configured on an Embedded PC: CX9000 configured with Windows CE (ARM).

Import into Delphi

The server interface description is published in a WSDL file (Web Service Definition Language). The WSDL description is imported into Delphi and converted by Delphi into Delphi units.

First of all create a new project (Windows Forms application Delphi .NET). Save the project. You can now import the WSDL file. In the Project Manager, right click with the mouse on the project name and select “Add Web Reference”.

A dialog opens showing Web service directories from IBM, Microsoft etc. However, we want to open the WSDL file from the data storage device.

The WSDL files from the TwinCAT ADS Web service can be found in the folder: ..TwinCAT\Ads API\TcAdsWebService\V100\... Navigate to the appropriate folder and select the WSDL file. In our case it is the WSDL file from the folder for the Windows CE (ARM) target platform.

Note:

There is no difference between the WSDL files for the XP/CE (X86 or ARM) platforms. I.e. it is always the same WSDL file. You can integrate the WSDL file from the CE/ARM folder in your consumer project and nonetheless still communicate with an ADS Web Service server on an XP platform.

The contents of the WSDL file are displayed in a dialog box.

Select “Add Web Reference”. The required units are generated automatically and added to the project.

Using the web service

In order to be able to use the web service you must integrate the web service unit in the main window unit. You can take the opportunity at the same time to integrate two further units that you will need in your project later: System.Text and System.Web.Services.Protocols

uses
System.Drawing, System.Collections, System.ComponentModel,
System.Windows.Forms, System.Data,
 WebReference.TcAdsWebService, System.Text,System.Web.Services.Protocols;

Now you can create an ADS Web service instance.

 private
{ Private Declarations }
TcWebService : WebReference.TcAdsWebService.TcAdsWebService;

And in the TwinForm constructor:

TcWebService := WebReference.TcAdsWebService.TcAdsWebService.Create();

The code completion will help you further. Type in TcWebService with a dot and look at the methods which are available.

We use the following methods in our example:

  • Read for reading the PLC variables;
  • Write for writing the PLC variables;
  • ReadState for reading the PLC server status;
  • WriteControl to change the PLC server status;
type TArrayOfByte = array of Byte;

procedure Read(netId: string; nPort: Integer; indexGroup: Cardinal; indexOffset: Cardinal; cbLen: Integer; out ppData: TArrayOfByte);
procedure Write(netId: string; nPort: Integer; indexGroup: Cardinal; indexOffset: Cardinal; pData: TArrayOfByte);
procedure ReadState(netId: string; nPort: Integer; out pAdsState: Integer; out pDeviceState: Integer);
procedure WriteControl(netId: string; nPort: Integer; adsState: Integer; deviceState: Integer; pData: TArrayOfByte);

netId: String with the network address of the TwinCAT target system. In our case the TwinCAT AMS NetID of the PC with the PLC runtime system;

nPort: TwinCAT ADS port number of the PLC runtime system;

indexGroup: Index group of the PLC variables to be read;

indexOffset: Index offset (byte-/bit offset) of the PLC variables to be read;

cbLen: Number of bytes which are to be read;

ppData: Variable in which the read data is saved (dynamic byte array);

pData: Variable with the data to be written (dynamic array);

adsState / pAdsState: PLC server status.

deviceState / pDeviceState: PLC device status;

The PLC application

PROGRAM MAIN
VAR
    VarBool		AT %MX0.0:	BOOL := TRUE;
    VarInt		AT %MB1:	INT := 123;
    VarString	AT %MB3:	STRING := 'Hello Automation';
END_VAR

Read PLC variables

procedure TWinForm.ReadData();
var cbLen, nIG, nIO   : Integer;
    data    : TArrayOfByte;
begin
  try
    // read BOOL at adress AT%MX0.0
    nIG   := $4021;
    nIO   := 0;
    cbLen := SizeOf(varBool);
    TcWebService.Read( sNetID, iPort, nIG, nIO, cbLen, data );
    varBool         := BitConverter.ToBoolean(data, 0);
    // read INT at adress AT%MB1
    nIG   := $4020;
    nIO   := 1;
    cbLen := SizeOf(varInt);
    TcWebService.Read( sNetID, iPort, nIG, nIO, cbLen, data );
    varInt          := BitConverter.ToInt16(data, 0);
    // read STRING at adress AT%MB3
    nIG   := $4020;
    nIO   := 3;
    cbLen := 81;
    TcWebService.Read( sNetID, iPort, nIG, nIO, cbLen, data );
    varString := System.Text.Encoding.Default.GetString(data,0, Length(data));
  except
    On E:SoapException do
      HandleSoapException(E.Message, E.HelpLink, E.Detail.InnerText);
  end;
end;

Write PLC variables

procedure TWinForm.WriteData();
var data    : TArrayOfByte;
    cbLen, nIG, nIO : Integer;
begin
  try
    // write BOOL at adress AT%MX0.0
    nIG   := $4021;
    nIO   := 0;
    data  := BitConverter.GetBytes(varBool);
    TcWebService.Write( sNetID, iPort, nIG, nIO, data );
    // write INT at adress AT%MB1
    nIG   := $4020;
    nIO   := 1;
    data  := BitConverter.GetBytes(varInt);
    TcWebService.Write( sNetID, iPort, nIG, nIO, data );
    // write STRING at adress AT%MB3
    nIG   := $4020;
    nIO   := 3;
    cbLen := System.Text.Encoding.Default.GetByteCount(varString);
    // Allocate one byte more! We need it to write the string end delimiter!.
    SetLength(data, cbLen + 1);
    System.Text.Encoding.Default.GetBytes( varString, 0, cbLen, data, 0);
    data[cbLen] := 0;
    TcWebService.Write( sNetID, iPort, nIG, nIO, data );
  except
    On E:SoapException do
      HandleSoapException(E.Message, E.HelpLink, E.Detail.InnerText);
  end;
end;

Read PLC status

procedure TWinForm.ReadState();
var adsState, deviceState : Integer;
sState : String;
begin
  try
    TcWebService.ReadState( sNetID, iPort, adsState, deviceState );
    case adsState of
      PLC_ADSSTATE_RUN:
        sState := 'RUN';
      PLC_ADSSTATE_STOP:
        sState := 'STOP';
    else
      sState := 'OTHER';
    end;
    StatusBar1.Panels.Item[0].Text := 'PLC server state: ' + sState;
  except
    On E:SoapException do
      HandleSoapException(E.Message, E.HelpLink, E.Detail.InnerText);
  end;
end;

Start/stop PLC

procedure TWinForm.WriteControl(adsState : Integer);
begin
  try
    TcWebService.WriteControl( sNetID, iPort, adsState, 0, nil );
  except
    On E:SoapException do
      HandleSoapException(E.Message, E.HelpLink, E.Detail.InnerText);
  end;
end;

Language / IDE | Extract the sample program
Delphi 8 for .NET | Sample01.exe


Notes on the documentation

This description is only intended for the use of trained specialists in control and automation engineering who are familiar with the applicable national standards.
It is essential that the following notes and explanations are followed when installing and commissioning these components.

The responsible staff must ensure that the application or use of the products described satisfy all the requirements for safety, including all the relevant laws, regulations, guidelines and standards.

Disclaimer

The documentation has been prepared with care. The products described are, however, constantly under development.
For that reason the documentation is not in every case checked for consistency with performance data, standards or other characteristics.
In the event that it contains technical or editorial errors, we retain the right to make alterations at any time and without warning.
No claims for the modification of products that have already been supplied may be made on the basis of the data, diagrams and descriptions in this documentation.

Trademarks

Beckhoff®, TwinCAT®, EtherCAT®, Safety over EtherCAT®, TwinSAFE® and XFC® are registered trademarks of and licensed by Beckhoff Automation GmbH.
Other designations used in this publication may be trademarks whose use by third parties for their own purposes could violate the rights of the owners.

Patent Pending

The TwinCAT Technology is covered, including but not limited to the following patent applications and patents:
EP0851348, US6167425 with corresponding applications or registrations in various other countries.

Copyright

© Beckhoff Automation GmbH & Co. KG, Germany.
The reproduction, distribution and utilization of this document as well as the communication of its contents to others without express authorization are prohibited.
Offenders will be held liable for the payment of damages. All rights reserved in the event of the grant of a patent, utility model or design.


Beckhoff Information System - English

TwinCAT ADS Web Service: JavaScript example

Consumer in JavaScript to read and write PLC variables

This sample explains how to create an ADS-WebService-Consumer to read and write PLC-Variables via ADS-HTTP.

Unzip the sample 'WebServiceTestConsumer (JavaScript)'.

1. Creating a WebService-Consumer

This sample uses the XMLHttpRequest object to communicate via SOAP Requests to the AdSWebService.
Copy the files "index.htm" and "xmlhttp.js" to the folder of the AdS Webservice (to create a AdsWebService you might consider reading this).
Change the host address in the URL, netId and port:
// The URL to your TcAdsWebService WebService
var url = "http://172.16.10.195/TcAdsWebService/TcAdsWebService.dll";
// Your local AmsNetId
var netId = "172.16.4.220.1.1";
// Your current PLCs runtime
var port = 801;
You may also change the refresh timer.

2. Reading PLC-variables

To read PLC-variables use the following function:
Read (netId, nPort, indexGroup, indexOffset, cbLen)

  • netId: String indicating the AMS-Net-Id of the PLC
  • nPort: Port-number of the Runtime-System
  • indexGroup: IndexGroup of the variables to read
  • indexOffset: First byte to read
  • cbRdLen: Number of bytes to read

You have to process the result of the Read function in the "processReqChange()" function.
The 2 functions convert the <ppData> values returned to the processReqChange() function to their corresponding type.
toString(string)
toInt(string)

Don't forget to use b64t2d(string) to decode the string before you use it.
To convert a bool just check if char at position 0 is '0':
result = (data.charCodeAt(0)!='0');

Example:
// Decode result string
data = b64t2d(data);

// First byte: Status (boolean)
bool = (data.charCodeAt(0) != '0');

// Second and third byte: Value (int)
integer = toInt(data.substr(1, 2));

// Fourth and fifth byte: MaxValue (int)
max = toInt(data.substr(3, 2));

// 5-86 byte: Time (string)
time = toString(data.substr(5, 81));

3. Write PLC-variables

Write (netId, nPort, indexGroup, indexOffset, cbWrLen, pwrData, type)
  • netId: String indicating the AMS-Net-Id of the PLC
  • nPort: Port-number of the Runtime-System
  • indexGroup: IndexGroup of the variable
  • indexOffset: First byte to write to
  • cbWrLen: Length of data to write
  • pwrData: Array containing the data to write
  • type: "bool", "int" or "string"

When the button is clicked the value from the <Input>-Tag with name "input_max" is retrieved from the website. This value is converted to an integer and afterwards send via the write command which target is the specified address.

<input type="submit" size="5" name="submit" value="Change" onclick="Write(netId, port, '16416', '3', '2', parseInt(document.all['input_max'].value), 'int')" />

4. PLC-program, IEC1131 daclaration of the variables:

PROGRAM MAIN
VAR
   PlcVarBool   AT %MW0 :BOOL := TRUE;
   PlcVarInt    AT %MW1 :INT := 0;
   PlcVarIntMax AT %MW3 :INT := 1000;
   PlcVarString AT %MD5 :STRING;
   TON1                 :TON;
   bool1                :BOOL;
   time1                :TIME;
END_VAR

5. PLC-program, Source Code:

PlcVarInt := PlcVarInt + 1;
IF PlcVarInt > PlcVarIntMax THEN
    PlcVarInt := 0;
END_IF

PlcVarBool := NOT PlcVarBool;

TON1(IN:=TRUE , PT:=t#5m , Q=>bool1 , ET=>time1 );
IF bool1 THEN
TON1(IN:=FALSE , PT:= , Q=> , ET=> );
END_IF

PlcVarString := TIME_TO_STRING(time1);

6. JavaScript, sourcecode

var success = 0, errors = 0, req, data;

function init()
{
    loop(refresh);
}

function loop(x)
{
    // Send soap read request via xmlhttprequest
    Read(netId, port, '16416', '0', '86');

    // Call loop again with x ms delay
    window.setTimeout("loop(" + x + ")", x);
}

// Parse the SOAP result of the xmlhttprequest
function processReqChange()
{
    /*
    readyStates:
    0 = uninitialized
    1 = loading
    2 = loaded
    3 = interactive
    4 = complete
    */

    if (req.readyState == 4)
    {
        // Check for status "OK"
        if (req.status == 200)
        {
            response = req.responseXML.documentElement;

            // Check the response for errors in the request
            try
            {
                errortext = response.getElementsByTagName('faultstring')[0].firstChild.data;

                try
                {
                    errorcode = response.getElementsByTagName('errorcode')[0].firstChild.data;
                }
                catch (e)
                {
                    errorcode = "-";
                }

                showerror(errortext + " ("+errorcode+")");
                return;
            }
            catch (e)
            {
                errorcode = 0;
            }

            // Check whether the response contains a  element. If so process it and retrieve the values.
            // If not it is a write request and therefore ignored.
            try
            {
                data = response.getElementsByTagName('ppData')[0].firstChild.data;

                // Since now the data is extracted from the response its contents need to be parsed so that the results can be displayed.
                try
                {
                    // Decode result string
                    data = b64t2d(data);

                    // First byte: Status (boolean)
                    bool = (data.charCodeAt(0) != '0');

                    // Second and third byte: Value (int)
                    integer = toInt(data.substr(1, 2));

                    // Fourth and fifth byte: MaxValue (int)
                    max = toInt(data.substr(3, 2));

                    // 5-86 byte: Time (string)
                    time = toString(data.substr(5, 81));
                }
                catch (e)
                {
                    showerror("Parsing Failed: " + e);
                    return;
                }

                // Display the results
                document.all["valuefield"].value = integer;
                pro = (integer / max) * 100;
                document.loadimage.width = pro * 3;

                document.all["maxfield"].value = max;
                document.all["timefield"].value = time;
                document.all["boolfield"].value = bool;

                if (bool==true)
                    document.all["boolfield"].className="blue";
                else
                    document.all["boolfield"].className="normal";
            }
            catch (e)
            {
                data = "";
                mode = "";
            }

            // Valid checks only: Set the status to "ok".
            document.all["status"].value = "ok";
            document.all["status"].className = "green";

            success++;
            document.all["success"].value = success;
        }
        else
        {
            // Request status is not correct: Display error message.
            showerror(req.statusText);
        }
    }
}

function showerror (text)
{
    errors++;
    document.all["status"].value = text;
    document.all["status"].className = "red";
    document.all["errors"].value = errors;
}

7. JavaScript, download:

WebServiceSampleJavaScript.zip