Notes on the documentation

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

It is the duty of the technical personnel to use the documentation published at the respective time of each installation and commissioning.

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.
We reserve the right to revise and change the documentation at any time and without prior announcement.
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®, EtherCAT G®, EtherCAT G10®, EtherCAT P®, Safety over EtherCAT®, TwinSAFE®, XFC®, XTS® and XPlanar® 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 EtherCAT Technology is covered, including but not limited to the following patent applications and patents:
EP1590927, EP1789857, EP1456722, EP2137893, DE102015105702
with corresponding applications or registrations in various other countries.

EtherCAT® is a registered trademark and patented technology, licensed by Beckhoff Automation GmbH, Germany.

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.


Overview

TwinCAT ADS WCF

Introduction

The TwinCAT ADS WCF Service based on ADS and provides an easy access to TwinCAT devices via Microsoft Windows Communication Foundation (WCF) technology.

Next steps
Installation
.NET Samples


WCF service requirements

TwinCAT ADS WCF

Requirements

Server

Supported operating system: Windows XP, XP Embedded, Embedded Standard 2009, Windows 7, Windows 8

TwinCAT Level: minimum TwinCAT2 CP or TwinCAT3 ADS

.NET Framework: minimum v2.0.50727

Supported by Windows CE: no

Client

Supported operating system: Windows XP, XP Embedded, Embedded Standard 2009, Windows 7, Windows 8

TwinCAT Level: no TwinCAT Installation is required

.NET Framework: minimum v2.0.50727

Supported by Windows CE: Yes

.NET Compact Framework: v3.5 (for CE)


ADS WCF Installation

TwinCAT ADS WCF

Service Installation

The following step descripes how to install the TwinCAT ADS WCF Service, which can be connected by a ADS WCF client.

1. Install libraries

Install the listed libraries into the "Global Assembly Cache" by copying them to "C:\WINDOWS\assembly" as Administrator:

  • "TwinCAT\AdsApi\TcAdsWcf\PollingDuplex\v3.0\System.ServiceModel.PollingDuplex.dll"
  • "TwinCAT\AdsApi\TcAdsWcf\PollingDuplex\v4.0\System.ServiceModel.PollingDuplex.dll"

2. Create Windows Service

Open the command prompt as Administrator and use the InstallUtil.exe (part of the .NET Framework) to create the Windows service:

You will be informed, if the service is installed ordinary:

Switch to "Control Panel\Administrative Tools\Services" and start the "TcAdsWcfHost" Service:

Open a browser and go to http://localhost:8003/TwinCAT/Ads/Wcf/TcAdsService to test the service. You will received following webpages:

Sample Overview

Note: If you want to uninstall the TwinCAT ADS WCF Service use the parameter -u of the InstallUtil.exe-Tool.


Create a WCF service reference in Visual Studio

In order to create a WCF service reference in Visual Studio you must choose the command Add Service Reference... under the Project menu.
This opens the Add Service Reference dialog:

In the dialog enter the http or the https based base address of the TcAdsService and press the GO button.
This will load the service meta data and create the needed client code.
After that the service reference will be listed in the Solution Explorer with the chosen namespace.


Overview

Description
Create a WCF service reference in Visual Studio
Create a WCF web reference in Visual Studio 2008

Microsoft .NET

Description
Accessing an array in the PLC
Event driven reading
Buffered Values
Reading and writing string variables
Handling SOAP ErrorFaults and specific WCF Exceptions

Microsoft Compact Framework

Description
Accessing an array in the PLC
Reading and writing string variables
Handling SOAP ErrorFaults and specific WCF Exceptions

Microsoft Silverlight

Description
Accessing an array in the PLC
Event driven reading
Reading and writing string variables
Handling SOAP ErrorFaults and specific WCF Exceptions


Accessing an array in the PLC

Requirements

Visual Studio 2010

TwinCAT ADS WCF 1.1.0.1

Description

Reading an array of integer variables from the PLC by the use of the TwinCAT ADS WCF service.
The TwinCAT.Ads DLL is used to read the data from the received byte array in an easy to handle way.

WPF (C#) application

using System.Windows;
using System.ServiceModel;
using TwinCAT.Ads;
using Sample01.TwinCAT.Ads.Wcf;

namespace Sample01
{
    public partial class MainWindow : Window
    {
        // If the netid string is empty, the TwinCAT ADS WCF service will use the TwinCAT Runtime on its host machine.
        private const string NETID = "";
        private const int PORT = 801;

        private TcAdsServiceSimplexClient wcfClient;

        public MainWindow ( )
        {
            InitializeComponent ( );

            // Initialize simplex client with BasicHttpBinding.
            wcfClient = new TcAdsServiceSimplexClient (
                    new BasicHttpBinding( BasicHttpSecurityMode.None ),
                    new EndpointAddress ( "http://localhost:8003/TwinCAT/Ads/Wcf/TcAdsService/UnsecBasicHttp" )
                );

            // Open connection to the WCF service.
            wcfClient.Open ( );
        }

        private void btnRead_Click ( object sender, RoutedEventArgs e )
        {
            // Create buffer as byte array which recieves the data.
            int buffLen = 100 * 2;

            // Read array from plc.
             byte[] buffer =  wcfClient.Read1(NETID, PORT, "MAIN.PLCVar", buffLen);

            // Create AdsStream and AdsBinaryReader for buffer handling.
            AdsStream dataStream = new AdsStream ( buffer );
            AdsBinaryReader binRead = new AdsBinaryReader ( dataStream );

            lbArray.Items.Clear ( );
            dataStream.Position = 0;
            for ( int i = 0; i < 100; i++ )
            {
                lbArray.Items.Add ( binRead.ReadInt16( ) );
            }
        }
    }
}

TcAdsWcf_Sample01.zip


Event driven reading

Requirements

Visual Studio 2010

TwinCAT ADS WCF 1.1.0.1

Description

Reading symbol data from the PLC by ADS notification callback on symbol change.
The TwinCAT.Ads DLL is used to read the data from the received byte array in an easy to handle way.

WPF (C#) application

using System;
using System.Windows;
using TwinCAT.Ads;
using Sample02.TcAdsWcf;
using System.ServiceModel;
using System.Windows.Threading;
using System.Threading;

namespace Sample02
{
    // ConcurrencyMode.Multiple and UseSynchronizationContext = false prevent the GUI from Deadlocks,
    // while waiting for a WCF response on the callback channel.
    [CallbackBehavior (
        ConcurrencyMode = ConcurrencyMode.Multiple,
        UseSynchronizationContext = false )]
    public partial class MainWindow : Window, ITcAdsServiceDuplexCallback
    {
         // If the netid string is empty, the TwinCAT ADS WCF service will use the TwinCAT Runtime on its host machine.
        private const string NETID = "";
        private const int PORT = 801;

        private TcAdsServiceDuplexClient wcfClient;
        private int[] handles = new int [ 7 ];

        public MainWindow ( )
        {
            InitializeComponent ( );

            // Initialize duplex client with NetTcpBinding.
            wcfClient = new TcAdsServiceDuplexClient (
                new InstanceContext ( this ),
                new NetTcpBinding ( SecurityMode.None ),
                new EndpointAddress ( "net.tcp://localhost:4508/TwinCAT/Ads/Wcf/TcAdsService/UnsecNetTcp" ) );

            // Open connection to the WCF service.
            wcfClient.Open ( );

            // Subscribe to AdsNotification and AdsNotificationError events.
            wcfClient.SubscribeAdsNotificationEvent ( NETID, PORT );
            wcfClient.SubscribeAdsNotificationErrorEvent ( NETID, PORT );

            // Register device notifications.
            handles [ 0 ] = wcfClient.AddDeviceNotification1 (
                NETID, PORT, "MAIN.boolVal", 1, TcAdsWcf.AdsTransMode.OnChange, 100, 0, null );
            handles [ 1 ] = wcfClient.AddDeviceNotification1 (
                NETID, PORT, "MAIN.intVal", 2, TcAdsWcf.AdsTransMode.OnChange, 100, 0, null );
            handles [ 2 ] = wcfClient.AddDeviceNotification1 (
                NETID, PORT, "MAIN.dintVal", 4, TcAdsWcf.AdsTransMode.OnChange, 100, 0, null );
            handles [ 3 ] = wcfClient.AddDeviceNotification1 (
                NETID, PORT, "MAIN.sintVal", 1, TcAdsWcf.AdsTransMode.OnChange, 100, 0, null );
            handles [ 4 ] = wcfClient.AddDeviceNotification1 (
                NETID, PORT, "MAIN.lrealVal", 8, TcAdsWcf.AdsTransMode.OnChange, 100, 0, null );
            handles [ 5 ] = wcfClient.AddDeviceNotification1 (
                NETID, PORT, "MAIN.realVal", 4, TcAdsWcf.AdsTransMode.OnChange, 100, 0, null );
            handles [ 6 ] = wcfClient.AddDeviceNotification1 (
                NETID, PORT, "MAIN.stringVal", 50, TcAdsWcf.AdsTransMode.OnChange, 100, 0, null );
        }

        #region ITcAdsServiceDuplexCallback Members

        public void AdsNotification ( string netId, int port, byte [ ] buffer, int length, int notificationHandle, int offset, long timeStamp, object userData )
        {
            // Create AdsStream and AdsBinaryReader for buffer handling.
            AdsStream adsStream = new AdsStream ( buffer );
            AdsBinaryReader binReader = new AdsBinaryReader ( adsStream );
            adsStream.Position = offset;

            // Choose action by notificationHandle value.
            // UI changes have to be invoked,
            // because the callback methods are called from a background thread.
            if ( notificationHandle == handles [ 0 ] )
            {
                string value = binReader.ReadBoolean ( ).ToString ( );
                Dispatcher.BeginInvoke (
                    DispatcherPriority.Input,
                    new ThreadStart ( ( ) =>
                    {
                        tbBool.Text = value;
                    } ) );
            }
            else if ( notificationHandle == handles [ 1 ] )
            {
                string value = binReader.ReadInt16 ( ).ToString ( );
                Dispatcher.BeginInvoke (
                    DispatcherPriority.Input,
                    new ThreadStart ( ( ) =>
                    {
                        tbInt.Text = value;
                    } ) );
            }
            else if ( notificationHandle == handles [ 2 ] )
            {
                string value = binReader.ReadInt32 ( ).ToString ( );
                Dispatcher.BeginInvoke (
                    DispatcherPriority.Input,
                    new ThreadStart ( ( ) =>
                    {
                        tbDint.Text = value;
                    } ) );
            }
            else if ( notificationHandle == handles [ 3 ] )
            {
                string value = binReader.ReadByte ( ).ToString ( );
                Dispatcher.BeginInvoke (
                    DispatcherPriority.Input,
                    new ThreadStart ( ( ) =>
                    {
                        tbSint.Text = value;
                    } ) );
            }
            else if ( notificationHandle == handles [ 4 ] )
            {
                string value = binReader.ReadDouble ( ).ToString ( );
                Dispatcher.BeginInvoke (
                    DispatcherPriority.Input,
                    new ThreadStart ( ( ) =>
                    {
                        tbLreal.Text = value;
                    } ) );
            }
            else if ( notificationHandle == handles [ 5 ] )
            {
                string value = binReader.ReadSingle ( ).ToString ( );
                Dispatcher.BeginInvoke (
                    DispatcherPriority.Input,
                    new ThreadStart ( ( ) =>
                    {
                        tbReal.Text = value;
                    } ) );
            }
            else if ( notificationHandle == handles [ 6 ] )
            {
                string value = binReader.ReadPlcString ( length );
                Dispatcher.BeginInvoke (
                    DispatcherPriority.Input,
                    new ThreadStart ( ( ) =>
                    {
                        tbString.Text = value;
                    } ) );
            }
        }

        public void AdsNotificationError ( string netId, int port, Exception error )
        {
            MessageBox.Show ( error.Message );
        }

        public void AdsStateChanged ( string netId, int port, TcAdsWcf.StateInfo state )
        {
            // Not needed
        }

        public void AdsSymbolVersionChanged ( string netId, int port )
        {
            // Not needed
        }

        public void AmsRouterNotification ( string netId, int port, TcAdsWcf.AmsRouterState state )
        {
            // Not needed
        }

        public void HeartBeat ( )
        {
            // Not needed
        }

        #endregion
    }
}

TcAdsWcf_Sample02.zip


Handling SOAP ErrorFaults and specific WCF Exceptions

Requirements

Visual Studio 2010

TwinCAT ADS WCF 1.1.0.1

C# console application

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TcAdsWcf_Sample09.TwinCAT.Ads.Wcf;
using System.ServiceModel;

namespace TcAdsWcf_Sample09
{
    class Program
    {
        static void Main ( string [ ] args )
        {
            // Initialize simplex client with BasicHttpBinding.
            TcAdsServiceSimplexClient wcfClient = new TcAdsServiceSimplexClient (
                    new BasicHttpBinding ( BasicHttpSecurityMode.None ),
                    new EndpointAddress ( "http://localhost:8003/TwinCAT/Ads/Wcf/TcAdsService/UnsecBasicHttp" )
                );

            // Open connection to the WCF service.
            wcfClient.Open ( );

            try
            {
                byte[] buffer = wcfClient.Read1("", 801, "BAD_VARNAME", 2);
            }
            catch ( FaultException fe )
            {
                // Will be raised if an ErrorFault was raised by a method of TwinCAT ADS WCF.
                if ( fe.GetType ( ).Equals (
                    typeof ( FaultException<ArgumentErrorFault> ) ) )
                {
                    FaultException<ArgumentErrorFault> feArg =
                        fe as FaultException<ArgumentErrorFault>;

                    Console.WriteLine ( "ErrorFault: ArgumentErrorFault" );
                    Console.WriteLine ( feArg.Message );
                }

                if ( fe.GetType ( ).Equals (
                    typeof ( FaultException<AdsErrorFault> ) ) )
                {
                    FaultException<AdsErrorFault> feAds =
                        fe as FaultException<AdsErrorFault>;

                    Console.WriteLine ( "ErrorFault: AdsErrorFault" );
                    Console.WriteLine ( feAds.Message );
                }

                if ( fe.GetType ( ).Equals (
                    typeof ( FaultException<AdsErrorErrorFault> ) ) )
                {
                    FaultException<AdsErrorErrorFault> feAdsErr =
                        fe as FaultException<AdsErrorErrorFault>;

                    Console.WriteLine ( "ErrorFault: AdsErrorErrorFault" );
                    Console.WriteLine ( feAdsErr.Message );
                    Console.WriteLine ( "ErrorCode: " + feAdsErr.Detail.ErrorCode );
                }

                if ( fe.GetType ( ).Equals (
                    typeof ( FaultException<UnexpectedErrorFault> ) ) )
                {
                    FaultException<UnexpectedErrorFault> feUnexpected =
                        fe as FaultException<UnexpectedErrorFault>;

                    Console.WriteLine ( "ErrorFault: UnexpectedErrorFault" );
                    Console.WriteLine ( feUnexpected.Message );
                }
            }
            catch ( CommunicationException ce )
            {
                // Will be raised if there is a communication problem with TwinCAT ADS WCF.
                Console.WriteLine ( "CommunicationException: " );
                Console.WriteLine ( ce.Message );
            }
            catch ( TimeoutException te )
            {
                // Will be raised if a requested timed out.
                Console.WriteLine ( "TimeoutException: " );
                Console.WriteLine ( te.Message );
            }
            catch ( Exception ex )
            {
                Console.WriteLine ( "Exception: " );
                Console.WriteLine ( ex.Message );
            }

            // Close connection to TwinCAT ADS WCF.
            wcfClient.Close ( );
            Console.ReadKey();
        }
    }
}

TcAdsWcf_Sample09.zip


Reading and writing string variables

Requirements

Visual Studio 2010

TwinCAT ADS WCF 1.1.0.1

Description

Read a string from a plc variable and display it in the visualization or write a string from the visualization to a plc variable.
The TwinCAT.Ads DLL is used to read the data from the received byte array, or to write the data into the byte array which will be send to the service, in an easy to handle way.

WPF (C#) application

using System.ServiceModel;
using System.Windows;
using TcAdsWcf_Sample03.TwinCAT.Ads.Wcf;
using TwinCAT.Ads;

namespace TcAdsWcf_Sample03
{
    public partial class MainWindow : Window
    {
        // If the netid string is empty, the TwinCAT ADS WCF service will use the TwinCAT Runtime on its host machine.
        private const string NETID = "";
        private const int PORT = 801;

        private TcAdsServiceSimplexClient wcfClient;

        public MainWindow ( )
        {
            InitializeComponent ( );

            // Initialize simplex client with BasicHttpBinding.
            wcfClient = new TcAdsServiceSimplexClient (
                new BasicHttpBinding ( BasicHttpSecurityMode.None ),
                new EndpointAddress ( "http://localhost:8003/TwinCAT/Ads/Wcf/TcAdsService/UnsecBasicHttp" ) );

            // Open connection to the WCF service.
            wcfClient.Open ( );
        }

        private void BtnRead_Click ( object sender, RoutedEventArgs e )
        {
            // Read the data from the plc into a byte array buffer.
            byte[] buffer = wcfClient.Read1(NETID, PORT, "MAIN.text", 30);

            // Initialize an AdsStream and an AdsBinaryWriter to read the data from the buffer.
            AdsStream stream = new AdsStream ( buffer );
            AdsBinaryReader binReader = new AdsBinaryReader ( stream );

            string text = binReader.ReadPlcString ( 30 );
            TbText.Text = text;
        }

        private void BtnWrite_Click ( object sender, RoutedEventArgs e )
        {
            // Create a byte array buffer.
            // Length of text +1 because of zero termination.
            byte[] buffer = new byte[ TbText.Text.Length + 1 ];

            // Initialize an AdsStream and an AdsBinaryWriter to write the text to the buffer.
            AdsStream stream = new AdsStream ( buffer );
            AdsBinaryWriter binWriter = new AdsBinaryWriter ( stream );
            binWriter.WritePlcString ( TbText.Text, TbText.Text.Length + 1 );

            // Send the buffer.
            wcfClient.Write1 ( NETID, PORT, "MAIN.text", buffer );
        }
    }
}

TcAdsWcf_Sample03.zip


Create a WCF web reference in Visual Studio 2008

In order to create a WCF web reference in Visual Studio 2008 you must choose the command Add Web Reference... under the Project menu.
This opens the Add Web Reference dialog:

In the dialog enter the http or the https based base address of the TcAdsService and press the GO button.
This will load the service meta data and create the needed client code.
After that the web reference will be listed in the Solution Explorer with the chosen namespace.


Accessing an array in the PLC

Requirements

Visual Studio 2008

Target Windows CE Device

TwinCAT ADS WCF 1.1.0.1

Description

Reading an array of integer variables from the PLC by the use of the TwinCAT ADS WCF service.
The TwinCAT.Ads DLL (Compat Framework) is used to read the data from the received byte array in an easy to handle way.

Compact Framework 3.5 (C#) application

using System;
using System.Windows.Forms;
using TcAdsWcf_Sample04.TwinCAT.Ads.Wcf;
using TwinCAT.Ads;

namespace TcAdsWcf_Sample04
{
    public partial class Form1 : Form
    {
        private const string NETID = "10.1.128.80.1.1";
        private const int PORT = 801;

        private UnsecBasicHttpEndpoint wcfClient;

        public Form1 ( )
        {
            InitializeComponent ( );

            // Initialize the WCF client.
            wcfClient = new UnsecBasicHttpEndpoint ( );
            wcfClient.Url = "http://10.1.128.80:8003/TwinCAT/Ads/Wcf/TcAdsService/UnsecBasicHttp";
        }

        private void btnRead_Click ( object sender, EventArgs e )
        {
            // Read the whole plc array into the byte array buffer.
            int buffLen = 100 * 2;
            byte[] buffer = wcfClient.Read1(NETID, PORT, true, "MAIN.PLCVar", buffLen, true );

            // Create an AdsStream and an AdsBinaryReader to read the data from the buffer.
            AdsStream stream = new AdsStream ( buffer );
            AdsBinaryReader binReader = new AdsBinaryReader ( stream );
            stream.Position = 0;

            lbArray.Items.Clear ( );
            for ( int i = 0; i < 100; i++ )
            {
                lbArray.Items.Add ( binReader.ReadInt16 ( ).ToString ( ) );
            }
        }
    }
}

TcAdsWcf_Sample04.zip


Reading and writing string variables

Requirements

Visual Studio 2008

Target Windows CE Device

TwinCAT ADS WCF 1.1.0.1

Description

Read a string from a plc variable and display it in the visualization or write a string from the visualization to a plc variable.
The TwinCAT.Ads DLL (Compact Framework) is used to read the data from the received byte array, or to write the data into the byte array which will be send to the service, in an easy to handle way.

Compact Framework 3.5 (C#) application

using System;
using System.Windows.Forms;
using TcAdsWcf_Sample05.TwinCAT.Ads.Wcf;
using TwinCAT.Ads;

namespace TcAdsWcf_Sample05
{
    public partial class Form1 : Form
    {
        private const string NETID = "10.1.128.80.1.1";
        private const int PORT = 801;

        private UnsecBasicHttpEndpoint wcfClient;

        public Form1 ( )
        {
            InitializeComponent ( );

            // Initialize the WCF client.
            wcfClient = new UnsecBasicHttpEndpoint ( );
            wcfClient.Url = "http://10.1.128.80:8003/TwinCAT/Ads/Wcf/TcAdsService/UnsecBasicHttp";
        }

        private void btnRead_Click ( object sender, EventArgs e )
        {
            // Read the whole plc array into the byte array buffer.
            byte[] buffer = wcfClient.Read1 (NETID, PORT, true, "MAIN.text", 30, true);

            // Create an AdsStream and an AdsBinaryReader to read the data from the buffer.
            AdsStream stream = new AdsStream ( buffer );
            AdsBinaryReader binReader = new AdsBinaryReader ( stream );

            tbText.Text = binReader.ReadPlcString ( 30 );
        }

        private void btnWrite_Click ( object sender, EventArgs e )
        {
            // Create a byte array buffer.
            // Length of text +1 because of zero termination.
            byte [ ] buffer = new byte [ tbText.Text.Length + 1 ];

            // Initialize an AdsStream and an AdsBinaryWriter to write the text to the buffer.
            AdsStream stream = new AdsStream ( buffer );
            AdsBinaryWriter binWriter = new AdsBinaryWriter ( stream );
            binWriter.WritePlcString ( tbText.Text, tbText.Text.Length + 1 );

            // Send the buffer.
            wcfClient.Write1 ( NETID, PORT, true, "MAIN.text", buffer );
        }
    }
}

TcAdsWcf_Sample05.zip


Handling SOAP ErrorFaults and specific WCF Exceptions

Requirements

Visual Studio 2008

Target Windows CE Device

TwinCAT ADS WCF 1.1.0.1

Compact Framework 3.5 (C#) application

using System;
using System.Windows.Forms;
using TcAdsWcf_Sample11.TwinCAT.Ads.WCF;
using System.Web.Services.Protocols;
using System.Xml;

namespace TcAdsWcf_Sample11
{
    public partial class Form1 : Form
    {
        private UnsecBasicHttpEndpoint wcfClient;

        public Form1 ( )
        {
            InitializeComponent ( );

            // Initialize the WCF client.
            wcfClient = new UnsecBasicHttpEndpoint ( );
            wcfClient.Url = "http://10.1.128.80:8003/TwinCAT/Ads/Wcf/TcAdsService/UnsecBasicHttp";
        }

        private void button1_Click ( object sender, EventArgs e )
        {
            try
            {
                // Error provocation
                byte [ ] buffer = wcfClient.Read1 ( "", 801, true, "BAD_VARNAME", 2, true);
            }
            catch ( SoapException soapEx )
            {
                if ( soapEx.Code.Name.Equals ( "AdsErrorFault" ) )
                {
                    MessageBox.Show ( "AdsErrorFault: \n" + soapEx.Message );
                }

                if ( soapEx.Code.Name.Equals ( "AdsErrorErrorFault" ) )
                {
                    // Parse details of serialized AdsErrorErrorFault object.
                    //  Create XmlNamespaceManager and add needed namespaces.
                    XmlNamespaceManager nsMgr = new XmlNamespaceManager ( soapEx.Detail.OwnerDocument.NameTable );
                    nsMgr.AddNamespace ( "type", "http://beckhoff.com/TwinCAT/Ads/Wcf/Types" );

                    // Get the value of the ErrorCode property.
                    string errCodeVal = string.Empty;
                    XmlNode errCodeNode = soapEx.Detail.SelectSingleNode (
                        "./type:AdsErrorErrorFault/type:ErrorCode", nsMgr );

                    errCodeVal = errCodeNode.InnerText;

                    MessageBox.Show ( string.Format (
                        "AdsErrorErrorFault: \n{0}\n\n ErrorCode: {1}",
                        soapEx.Message, errCodeVal ) );
                }

                if ( soapEx.Code.Name.Equals ( "ArgumentErrorFault" ) )
                {
                    MessageBox.Show ( "ArgumentErrorFault: \n" + soapEx.Message );
                }

                if ( soapEx.Code.Name.Equals ( "UnexpectedErrorFault" ) )
                {
                    MessageBox.Show ( "UnexpectedErrorFault: \n" + soapEx.Message );
                }
            }
            catch ( Exception ex )
            {
                MessageBox.Show ( "Exception: \n" + ex.Message );
            }
        }
    }
}

TcAdsWcf_Sample11.zip


Accessing an array in the PLC

Requirements

Visual Studio 2010

Silverlight 4 Tools

TwinCAT ADS WCF 1.1.0.1

Description

Reading an array of integer variables from the PLC by the use of the TwinCAT ADS WCF service.
The TwinCAT.Ads.SL DLL (Silverlight) is used to read the data from the received byte array in an easy to handle way.

While using the WCF service within a Silverlight application, all methods of the used context interface are appended with the postfix Async.
And there is a extra callback method for each method with the postfix Completed too.

Example: Read1 -> Read1Async, Read1Completed

This is important because silverlight allows asynchronous communication only. A read action by the use of the Read1 method is requested by the use of the Read1Async method and the response will raise the Read1Completed callback

Silverlight 4 application

using System;
using System.ServiceModel;
using System.Windows;
using System.Windows.Controls;
using TcAdsWcf_Sample06.TwinCAT.Ads.Wcf;
using TwinCAT.Ads.SL;

namespace TcAdsWcf_Sample06
{
    public partial class MainPage : UserControl
    {
        // If the netid string is empty, the TwinCAT ADS WCF service will use the TwinCAT Runtime on its host machine.
        private const string NETID = "";
        private const int PORT = 801;

        private TcAdsServiceSimplexClient wcfClient;

        public MainPage ( )
        {
            InitializeComponent ( );

            // Initialize WCF service client.
            wcfClient = new TcAdsServiceSimplexClient (
                new BasicHttpBinding ( ),
                new EndpointAddress ( "http://localhost:8003/TwinCAT/Ads/Wcf/TcAdsService/UnsecBasicHttp" ) );

            // Register for Read1Completed Event
            wcfClient.Read1Completed += new EventHandler<Read1CompletedEventArgs1>(wcfClient_Read1Completed);
        }

        private void wcfClient_Read1Completed(object sender, Read1CompletedEventArgs1 e)
        {
            // Create AdsStream and AdsBinaryReader for buffer handling.
            AdsStream stream = new AdsStream(e.Result);
            AdsBinaryReader binReader = new AdsBinaryReader(stream);
            stream.Position = 0;

            lbArray.Items.Clear();
            for (int i = 0; i < 100; i++)
            {
                lbArray.Items.Add(binReader.ReadInt16());
            }
        }

        private void btnRead_Click ( object sender, RoutedEventArgs e )
        {
            // Read array.
            int buffLen = 100 * 2;
            wcfClient.Read1Async(NETID, PORT, "MAIN.PLCVar", buffLen, null);
        }
    }
}

TcAdsWcf_Sample06.zip


Event driven reading

Requirements

Visual Studio 2010

Silverlight 4 Tools

TwinCAT ADS WCF 1.1.0.1

Description

Reading symbol data from the PLC by ADS notification callback on symbol change.
The TwinCAT.Ads.SL DLL (Silverlight) is used to read the data from the recieved byte array in an easy to handle way.

While using the WCF service within a Silverlight application, all methods of the used context interface are appended with the postfix Async.
And there is a extra callback method for each method with the postfix Completed too.

Example: Read1 -> Read1Async, Read1Completed

This is important because silverlight allows asynchronous communication only. A read action by the use of the Read1 method is requested by the use of the Read1Async method and the response will raise the Read1Completed callback

Silverlight 4 application

using System;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.Windows.Controls;
using TcAdsWcf_Sample07.TwinCAT.Ads.Wcf;
using TwinCAT.Ads.SL;

namespace TcAdsWcf_Sample07
{
    public partial class MainPage : UserControl
    {
        // If the netid string is empty, the TwinCAT ADS WCF service will use the TwinCAT Runtime on its host machine.
        private const string NETID = "";
        private const int PORT = 801;

        private TcAdsServiceDuplexClient wcfClient;
        private int[] handles = new int [ 7 ];

        public MainPage ( )
        {
            InitializeComponent ( );

            // Initialize WCF client.
            wcfClient = new TcAdsServiceDuplexClient(
                new PollingDuplexHttpBinding(
                    PollingDuplexHttpSecurityMode.None,
                    PollingDuplexMode.MultipleMessagesPerPoll ),
                new EndpointAddress ( "http://localhost:8003/TwinCAT/Ads/Wcf/TcAdsService/UnsecPollingDuplex4" ) );

            // Register asynchronous EventHandler.
            wcfClient.AddDeviceNotification1Completed += new EventHandler<AddDeviceNotification1CompletedEventArgs> ( wcfClient_AddDeviceNotification1Completed );

            // Register CallbackChannel EventHandler.
            wcfClient.AdsNotificationReceived += new EventHandler<AdsNotificationReceivedEventArgs> ( wcfClient_AdsNotificationReceived );

            // Subscribe to the AdsNotificationEvent.
            wcfClient.SubscribeAdsNotificationEventAsync ( NETID, PORT );

            // Add device notifications.
            wcfClient.AddDeviceNotification1Async (
                NETID, PORT, "MAIN.boolVal", 1, AdsTransMode.OnChange, 100, 0, null, 0 );
            wcfClient.AddDeviceNotification1Async (
                NETID, PORT, "MAIN.intVal", 2, AdsTransMode.OnChange, 100, 0, null, 1 );
            wcfClient.AddDeviceNotification1Async (
                 NETID, PORT, "MAIN.dintVal", 4, AdsTransMode.OnChange, 100, 0, null, 2 );
            wcfClient.AddDeviceNotification1Async (
                NETID, PORT, "MAIN.sintVal", 1, AdsTransMode.OnChange, 100, 0, null, 3 );
            wcfClient.AddDeviceNotification1Async (
                NETID, PORT, "MAIN.lrealVal", 8, AdsTransMode.OnChange, 100, 0, null, 4 );
            wcfClient.AddDeviceNotification1Async (
                NETID, PORT, "MAIN.realVal", 4, AdsTransMode.OnChange, 100, 0, null, 5 );
            wcfClient.AddDeviceNotification1Async (
                NETID, PORT, "MAIN.stringVal", 50, AdsTransMode.OnChange, 100, 0, null, 6 );
        }

        private void wcfClient_AddDeviceNotification1Completed ( object sender, AddDeviceNotification1CompletedEventArgs e )
        {
            int index = ( int ) e.UserState;
            handles [ index ] = e.Result;
        }

        private void wcfClient_AdsNotificationReceived ( object sender, AdsNotificationReceivedEventArgs e )
        {
            // Create AdsStream and AdsBinaryReader for buffer handling.
            AdsStream adsStream = new AdsStream ( e.buffer );
            AdsBinaryReader binReader = new AdsBinaryReader ( adsStream );
            adsStream.Position = e.offset;

            // Identify notification by handle and update GUI.
            if ( e.notificationHandle == handles [ 0 ] )
            {
                textBoxBool.Text = binReader.ReadBoolean ( ).ToString ( );
            }
            else if ( e.notificationHandle == handles [ 1 ] )
            {
                textBoxInt.Text = binReader.ReadInt16 ( ).ToString ( );
            }
            else if ( e.notificationHandle == handles [ 2 ] )
            {
                textBoxDint.Text = binReader.ReadInt32 ( ).ToString ( );
            }
            else if ( e.notificationHandle == handles [ 3 ] )
            {
                textBoxSint.Text = binReader.ReadByte ( ).ToString ( );
            }
            else if ( e.notificationHandle == handles [ 4 ] )
            {
               textBoxLreal.Text = binReader.ReadDouble ( ).ToString ( );
            }
            else if ( e.notificationHandle == handles [ 5 ] )
            {
                textBoxReal.Text = binReader.ReadSingle ( ).ToString ( );
            }
            else if ( e.notificationHandle == handles [ 6 ] )
            {
                textBoxString.Text = binReader.ReadPlcString ( e.length ).ToString ( );
            }
        }
    }
}

TcAdsWcf_Sample07.zip


Reading and writing string variables

Requirements

Visual Studio 2010

Silverlight 4 Tools

TwinCAT ADS WCF

Description

Read a string from a plc variable and display it in the visualization or write a string from the visualization to a plc variable.
The TwinCAT.Ads.SL DLL (Silverlight) is used to read the data from the recieved byte array in an easy to handle way.

While using the WCF service within a Silverlight application, all methods of the used context interface are appended with the postfix Async.
And there is a extra callback method for each method with the postfix Completed too.

Example: Read1 -> Read1Async, Read1Completed

This is important because silverlight allows asynchronous communication only. A read action by the use of the Read1 method is requested by the use of the Read1Async method and the response will raise the Read1Completed callback

Silverlight 4 application

using System;
using System.ServiceModel;
using System.Windows;
using System.Windows.Controls;
using TcAdsWcf_Sample08.TwinCAT.Ads.Wcf;
using TwinCAT.Ads.SL;

namespace TcAdsWcf_Sample08
{
    public partial class MainPage : UserControl
    {
        // If the netid string is empty, the TwinCAT ADS WCF service will use the TwinCAT Runtime on its host machine.
        private const string NETID = "";
        private const int PORT = 801;

        private TcAdsServiceSimplexClient wcfClient;

        public MainPage ( )
        {
            InitializeComponent ( );

            wcfClient = new TcAdsServiceSimplexClient (
                    new BasicHttpBinding ( ),
                    new EndpointAddress ( "http://localhost:8003/TwinCAT/Ads/Wcf/TcAdsService/UnsecBasicHttp" ));

            wcfClient.Read1Completed += new EventHandler<Read1CompletedEventArgs1>(wcfClient_Read1Completed);
        }

        private void wcfClient_Read1Completed(object sender, Read1CompletedEventArgs1 e)
        {
            // Create AdsStream and AdsBinaryReader for buffer handling.
            AdsStream stream = new AdsStream(e.Result);
            AdsBinaryReader binReader = new AdsBinaryReader(stream);
            stream.Position = 0;

            tbText.Text = binReader.ReadPlcString(30);
        }

        private void btnRead_Click ( object sender, RoutedEventArgs e )
        {
            // Read text asynchronous.
            wcfClient.Read1Async ( NETID, PORT, "MAIN.text", 30, null );
        }

        private void btnWrite_Click ( object sender, RoutedEventArgs e )
        {
            // Create a byte array buffer.
            // Length of text +1 because of zero termination.
            byte [ ] buffer = new byte [ tbText.Text.Length + 1 ];

            // Initialize an AdsStream and an AdsBinaryWriter to write the text to the buffer.
            AdsStream stream = new AdsStream ( buffer );
            AdsBinaryWriter binWriter = new AdsBinaryWriter ( stream );
            binWriter.WritePlcString ( tbText.Text, tbText.Text.Length + 1 );

            // Send the buffer.
            wcfClient.Write1Async ( NETID, PORT, "MAIN.text", buffer );
        }
    }
}

TcAdsWcf_Sample08.zip


Handling SOAP ErrorFaults and specific WCF Exceptions

Requirements

Visual Studio 2010

Silverlight 4 Tools

TwinCAT ADS WCF 1.1.0.1

Silverlight 4 application

using System;
using System.Windows;
using System.Windows.Controls;
using TcAdsWcf_Sample10.TwinCAT.Ads.Wcf;
using System.ServiceModel;

namespace TcAdsWcf_Sample10
{
    public partial class MainPage : UserControl
    {
        private TcAdsServiceSimplexClient wcfClient;

        public MainPage ( )
        {
            InitializeComponent ( );

            // Create the TwinCAT ADS WCF client.
            wcfClient = new TcAdsServiceSimplexClient (
                    new BasicHttpBinding ( BasicHttpSecurityMode.None ),
                    new EndpointAddress ( "http://localhost:8003/TwinCAT/Ads/Wcf/TcAdsService/UnsecBasicHttp" )
                );

            // Register Read1Completed EventHandler for Read1Async method.
            wcfClient.Read1Completed += new EventHandler<Read1CompletedEventArgs1>(wcfClient_Read1Completed);
        }

        private void Button_Click ( object sender, RoutedEventArgs e )
        {
            // Call Read1Async method with an invalid TwinCAT ADS Symbol name.
            wcfClient.Read1Async ( "", 801, "BAD_VARNAME", 2 );
        }

        private void wcfClient_Read1Completed(object sender, Read1CompletedEventArgs1 e)
        {
            if ( e.Error != null )
            {
                // An error occured while Read1Async was in process.

                if ( e.Error.GetType ( ).Equals (
                    typeof ( FaultException<AdsErrorFault> ) ) )
                {
                    FaultException<AdsErrorFault> fe
                        = e.Error as FaultException<AdsErrorFault>;

                    System.Diagnostics.Debug.WriteLine ( "AdsErrorFault: " );
                    System.Diagnostics.Debug.WriteLine ( fe.Message );
                }

                if ( e.Error.GetType ( ).Equals (
                    typeof ( FaultException<AdsErrorErrorFault> ) ) )
                {
                    FaultException<AdsErrorErrorFault> fe
                        = e.Error as FaultException<AdsErrorErrorFault>;

                    System.Diagnostics.Debug.WriteLine ( "AdsErrorErrorFault: " );
                    System.Diagnostics.Debug.WriteLine ( fe.Message );
                }

                if ( e.Error.GetType ( ).Equals (
                    typeof ( FaultException<ArgumentErrorFault> ) ) )
                {
                    FaultException<ArgumentErrorFault> fe
                        = e.Error as FaultException<ArgumentErrorFault>;

                    System.Diagnostics.Debug.WriteLine ( "ArgumentErrorFault: " );
                    System.Diagnostics.Debug.WriteLine ( fe.Message );
                }

                if ( e.Error.GetType ( ).Equals (
                    typeof ( FaultException<UnexpectedErrorFault> ) ) )
                {
                    FaultException<UnexpectedErrorFault> fe
                        = e.Error as FaultException<UnexpectedErrorFault>;

                    System.Diagnostics.Debug.WriteLine ( "UnexpectedErrorFault: " );
                    System.Diagnostics.Debug.WriteLine ( fe.Message );
                }

                if ( e.Error.GetType ( ).Equals (
                    typeof ( CommunicationException ) ) )
                {
                    CommunicationException ce = e.Error as CommunicationException;

                    System.Diagnostics.Debug.WriteLine ( "CommunicationException: " );
                    System.Diagnostics.Debug.WriteLine ( ce.Message );
                }

                if ( e.Error.GetType ( ).Equals (
                   typeof ( TimeoutException ) ) )
                {
                    TimeoutException te = e.Error as TimeoutException;

                    System.Diagnostics.Debug.WriteLine ( "TimeoutException: " );
                    System.Diagnostics.Debug.WriteLine ( te.Message );
                }

                if ( e.Error.GetType ( ).Equals (
                   typeof ( Exception ) ) )
                {
                    System.Diagnostics.Debug.WriteLine ( "Exception: " );
                    System.Diagnostics.Debug.WriteLine ( e.Error.Message );
                }

                return;
            }

            // No error occured.
            System.Diagnostics.Debug.WriteLine ( "Completed without error!" );
        }
    }
}

TcAdsWcf_Sample10.zip