TcAdsWebService.js

TcAdsWebService.js

The TcAdsWebService.js JavaScript Library provides objects for an easier usage of the TcAdsWebService to cross platform applications.

Samples
Cyclic reading of multiple variables with sumcommando
Writing multiple variables with sumcommando
Description Accessing an array in the PLC Event driven reading Reading and writing string variables


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.


TcAdsWebService.js Configuration

TcAdsWebService.js

Configuration

The TcAdsWebService.js uses the TcAdsWebService. Therefore you need to install the service first.

Please check our manual and test the URL of the TcAdsWebService, for example:

http://<ip-adress or name of PC device>/tcadswebservice/tcadswebservice.dll

Examples:

http://192.168.0.1/tcadswebservice/tcadswebservice.dll
http://localhost/tcadswebservice/tcadswebservice.dll

Add virtual directory

For a new website a new virtual directory is needed for the internet information server (IIS). Switch to the configuration tool of the IIS (control panel/ adminstrative tools) and add a new virtual directory for your website.

Create an aliase for your URL and select the physical path of the HTML files:

In this example your website can be reached with following URL: http://<ip-adress or name of PC device>/Machine

Notice: For Windows CE plattforms create a subdirectory in /Hard Disk/WWW for your website.


Cyclic reading of multiple variables with sumcommando

Description:

This sample shows how to read multiple variables cyclic by use of a read sumcommando.

Notice: Generally HTTP-traffic is more efficient by transportting bigger data packets instead of many small packets. Therefore please use ADS sum commandos to collect your data.

ToDo:

  • Download the TcAdsJavaScript.js_Sample01.zip
  • Start the PLC project
  • Copy the default.htm and TcAdsWebService.js to your configured virtual directory
  • Adjust NETID, PORT and SERVICE_URL if you use the TcAdsWebservice of a remote pc
<!DOCTYPE html>
<html>
<head>
    <title>TcAdsWebService.js Sample01</title>
    <script type="text/javascript" src="TcAdsWebService.js"></script>
    <script type="text/javascript">
        (function () {

            var NETID = ""; // Empty string for local machine;
            var PORT = "801"; // TC2 PLC Runtime = 801, TC3 PLC Runtime = 851
            var SERVICE_URL = "http://localhost/TcAdsWebService/TcAdsWebService.dll"; // HTTP path to the TcAdsWebService;

            var client = new TcAdsWebService.Client(SERVICE_URL, null, null);

            var general_timeout = 500;

            var readLoopID = null;
            var readLoopDelay = 500;

            var readSymbolValuesData = null;

            // Array of symbol names to read;
            var handlesVarNames = [
                    "MAIN.byteValue",
                    "MAIN.wordValue",
                    "MAIN.dwordValue",
                    "MAIN.sintValue",
                    "MAIN.intValue",
                    "MAIN.dintValue",
                    "MAIN.realValue",
                    "MAIN.lrealValue"
                ];

            // Occurs if the window has loaded;
            window.onload = (function () {

                // Create sumcommando for reading twincat symbol handles by symbol name;
                var handleswriter = new TcAdsWebService.DataWriter();

                // Write general information for each symbol handle to the TcAdsWebService.DataWriter object;
                for (var i = 0; i < handlesVarNames.length; i++) {
                    handleswriter.writeDINT(TcAdsWebService.TcAdsReservedIndexGroups.SymbolHandleByName);
                    handleswriter.writeDINT(0);
                    handleswriter.writeDINT(4); // Expected size; A handle has a size of 4 byte;
                    handleswriter.writeDINT(handlesVarNames[i].length); // The length of the symbol name string;
                }

                // Write symbol names after the general information to the TcAdsWebService.DataWriter object;
                for (var i = 0; i < handlesVarNames.length; i++) {
                    handleswriter.writeString(handlesVarNames[i]);
                }

                // Send the list-read-write command to the TcAdsWebService by use of the readwrite function of the TcAdsWebService.Client object;
                client.readwrite(
                    NETID,
                    PORT,
                    0xF082, 	// IndexGroup = ADS list-read-write command; Used to request handles for twincat symbols;
                    handlesVarNames.length, // IndexOffset = Count of requested symbol handles;
                    (handlesVarNames.length * 4) + (handlesVarNames.length * 8), // Length of requested data + 4 byte errorcode and 4 byte length per twincat symbol;
                    handleswriter.getBase64EncodedData(),
                    RequestHandlesCallback,
                    null,
                    general_timeout,
                    RequestHandlesTimeoutCallback,
                    true);

            });

            // Occurs if the readwrite for the sumcommando has finished;
            var RequestHandlesCallback = (function (e, s) {

                if (e && e.isBusy) {
                    // HANDLE PROGRESS TASKS HERE;
                    var message = "Requesting handles...";
                    td_byteValue.innerHTML = message;
                    td_wordValue.innerHTML = message;
                    td_dwordValue.innerHTML = message;
                    td_sintValue.innerHTML = message;
                    td_intValue.innerHTML = message;
                    td_dintValue.innerHTML = message;
                    td_realValue.innerHTML = message;
                    td_lrealValue.innerHTML = message;
                    // Exit callback function because request is still busy;
                    return;
                }

                if (e && !e.hasError) {

                    // Get TcAdsWebService.DataReader object from TcAdsWebService.Response object;
                    var reader = e.reader;

                    // Read error code and length for each handle;
                    for (var i = 0; i < handlesVarNames.length; i++) {

                        var err = reader.readDWORD();
                        var len = reader.readDWORD();

                        if (err != 0) {
                            div_log.innerHTML = "Handle error!";
                            return;
                        }

                    }

                    // Read handles from TcAdsWebService.DataReader object;
                    var hByteValue = reader.readDWORD();
                    var hWordValue = reader.readDWORD();
                    var hDwordValue = reader.readDWORD();
                    var hSintValue = reader.readDWORD();
                    var hIntValue = reader.readDWORD();
                    var hDintValue = reader.readDWORD();
                    var hRealValue = reader.readDWORD();
                    var hLrealValue = reader.readDWORD();

                    // Create sum commando to read symbol values based on the handle
                    var readSymbolValuesWriter = new TcAdsWebService.DataWriter();

                    //  "MAIN.byteValue" // BYTE
                    readSymbolValuesWriter.writeDINT(TcAdsWebService.TcAdsReservedIndexGroups.SymbolValueByHandle); // IndexGroup
                    readSymbolValuesWriter.writeDINT(hByteValue); // IndexOffset = The target handle
                    readSymbolValuesWriter.writeDINT(1); // size to read

                    //  "MAIN.wordValue" // WORD
                    readSymbolValuesWriter.writeDINT(TcAdsWebService.TcAdsReservedIndexGroups.SymbolValueByHandle); // IndexGroup
                    readSymbolValuesWriter.writeDINT(hWordValue); // IndexOffset = The target handle
                    readSymbolValuesWriter.writeDINT(2); // size to read

                    //  "MAIN.dwordValue" // DWORD
                    readSymbolValuesWriter.writeDINT(TcAdsWebService.TcAdsReservedIndexGroups.SymbolValueByHandle); // IndexGroup
                    readSymbolValuesWriter.writeDINT(hDwordValue); // IndexOffset = The target handle
                    readSymbolValuesWriter.writeDINT(4); // size to read

                    //  "MAIN.sintValue" // SINT
                    readSymbolValuesWriter.writeDINT(TcAdsWebService.TcAdsReservedIndexGroups.SymbolValueByHandle); // IndexGroup
                    readSymbolValuesWriter.writeDINT(hSintValue); // IndexOffset = The target handle
                    readSymbolValuesWriter.writeDINT(1); // size to read

                    //  "MAIN.intValue" // INT
                    readSymbolValuesWriter.writeDINT(TcAdsWebService.TcAdsReservedIndexGroups.SymbolValueByHandle); // IndexGroup
                    readSymbolValuesWriter.writeDINT(hIntValue); // IndexOffset = The target handle
                    readSymbolValuesWriter.writeDINT(2); // size to read

                    //  "MAIN.dintValue" // DINT
                    readSymbolValuesWriter.writeDINT(TcAdsWebService.TcAdsReservedIndexGroups.SymbolValueByHandle); // IndexGroup
                    readSymbolValuesWriter.writeDINT(hDintValue); // IndexOffset = The target handle
                    readSymbolValuesWriter.writeDINT(4); // size to read

                    //  "MAIN.realValue" // REAL
                    readSymbolValuesWriter.writeDINT(TcAdsWebService.TcAdsReservedIndexGroups.SymbolValueByHandle); // IndexGroup
                    readSymbolValuesWriter.writeDINT(hRealValue); // IndexOffset = The target handle
                    readSymbolValuesWriter.writeDINT(4); // size to read

                    //  "MAIN.lrealValue" // LREAL
                    readSymbolValuesWriter.writeDINT(TcAdsWebService.TcAdsReservedIndexGroups.SymbolValueByHandle); // IndexGroup
                    readSymbolValuesWriter.writeDINT(hLrealValue); // IndexOffset = The target handle
                    readSymbolValuesWriter.writeDINT(8); // size to read

                    // Get Base64 encoded data from TcAdsWebService.DataWriter;
                    readSymbolValuesData = readSymbolValuesWriter.getBase64EncodedData();

                    // Start cyclic reading of symbol values;
                    readLoopID = window.setInterval(ReadLoop, readLoopDelay);

                } else {

                    if (e.error.getTypeString() == "TcAdsWebService.ResquestError") {
                        // HANDLE TcAdsWebService.ResquestError HERE;
                        div_log.innerHTML = "Error: StatusText = " + e.error.statusText + " Status: " + e.error.status;
                    }
                    else if (e.error.getTypeString() == "TcAdsWebService.Error") {
                        // HANDLE TcAdsWebService.Error HERE;
                        div_log.innerHTML = "Error: ErrorMessage = " + e.error.errorMessage + " ErrorCode: " + e.error.errorCode;
                    }

                }

            });

            // Occurs if the readwrite for the sumcommando to request symbol handles runs into timeout;
            var RequestHandlesTimeoutCallback = (function () {
                // HANDLE TIMEOUT HERE;
                div_log.innerHTML = "Requuest handles timeout!";
            });

            // Interval callback for cyclic reading;
            var ReadLoop = (function () {

                // Send the read-read-write command to the TcAdsWebService by use of the readwrite function of the TcAdsWebService.Client object;
                client.readwrite(
                    NETID,
                    PORT,
                    0xF080, // 0xF080 = Read command;
                    8, // IndexOffset = Variables count;
                    26 + (8 * 4), // Length of requested data + 4 byte errorcode per variable;
                    readSymbolValuesData,
                    ReadCallback,
                    null,
                    general_timeout,
                    ReadTimeoutCallback,
                    true);

            });

            // Occurs if the read-read-write command has finished;
            var ReadCallback = (function (e, s) {

                if (e && e.isBusy) {
                    // HANDLE PROGRESS TASKS HERE;
                    // Exit callback function because request is still busy;
                    return;
                }

                if (e && !e.hasError) {

                    var reader = e.reader;

                    // Read error codes from begin of TcAdsWebService.DataReader object;
                    for (var i = 0; i < handlesVarNames.length; i++) {
                        var err = reader.readDWORD();
                        if (err != 0) {
                            div_log.innerHTML = "Symbol error!";
                            return;
                        }
                    }

                    //  "MAIN.byteValue" // BYTE
                    var byteValue = reader.readBYTE();

                    //  "MAIN.wordValue" // WORD
                    var wordValue = reader.readWORD();

                    //  "MAIN.dwordValue" // DWORD
                    var dwordValue = reader.readDWORD();

                    //  "MAIN.sintValue" // SINT
                    var sintValue = reader.readSINT();

                    //  "MAIN.intValue" // INT
                    var intValue = reader.readINT();

                    //  "MAIN.dintValue" // DINT
                    var dintValue = reader.readDINT();

                    //  "MAIN.realValue" // REAL
                    var realValue = reader.readREAL();

                    //  "MAIN.lrealValue" // LREAL
                    var lrealValue = reader.readLREAL();

                    // Write data to the user interface;
                    td_byteValue.innerHTML = byteValue;
                    td_wordValue.innerHTML = wordValue;
                    td_dwordValue.innerHTML = dwordValue;
                    td_sintValue.innerHTML = sintValue;
                    td_intValue.innerHTML = intValue;
                    td_dintValue.innerHTML = dintValue;
                    td_realValue.innerHTML = realValue;
                    td_lrealValue.innerHTML = lrealValue;

                } else {

                    if (e.error.getTypeString() == "TcAdsWebService.ResquestError") {
                        // HANDLE TcAdsWebService.ResquestError HERE;
                        div_log.innerHTML = "Error: StatusText = " + e.error.statusText + " Status: " + e.error.status;
                    }
                    else if (e.error.getTypeString() == "TcAdsWebService.Error") {
                        // HANDLE TcAdsWebService.Error HERE;
                        div_log.innerHTML = "Error: ErrorMessage = " + e.error.errorMessage + " ErrorCode: " + e.error.errorCode;
                    }
                }

            });

            // Occurs if the read-read-write command runs into timeout;
            var ReadTimeoutCallback = (function () {
                // HANDLE TIMEOUT HERE;
                div_log.innerHTML = "Read timeout!";
            });

        })();
    </script>
</head>
<body>
    <h1>TcAdsWebService.js Sample01</h1>
    <h2>Cyclic reading of multiple variables with sumcommando!</h2>
    <table>
        <tr>
            <td>MAIN.byteValue:</td>
            <td id="td_byteValue"></td>
        </tr>
        <tr>
            <td>MAIN.wordValue:</td>
            <td id="td_wordValue"></td>
        </tr>
        <tr>
            <td>MAIN.dwordValue:</td>
            <td id="td_dwordValue"></td>
        </tr>
        <tr>
            <td>MAIN.sintValue:</td>
            <td id="td_sintValue"></td>
        </tr>
        <tr>
            <td>MAIN.intValue:</td>
            <td id="td_intValue"></td>
        </tr>
        <tr>
            <td>MAIN.dintValue:</td>
            <td id="td_dintValue"></td>
        </tr>
        <tr>
            <td>MAIN.realValue:</td>
            <td id="td_realValue"></td>
        </tr>
        <tr>
            <td>MAIN.lrealValue:</td>
            <td id="td_lrealValue"></td>
        </tr>
    </table>
    <div id="div_log"></div>
</body>
</html>


Cyclic reading of multiple variables with sumcommando

TcAdsWebService.js

Writing multiple variables with sumcommando

Description

This sample shows how to write multiple variables by use of a write sumcommando.

Notice: Generally HTTP-traffic is more efficient by transporting bigger data packets instead of many small packets. Therefore please use ADS sum commandos to collect your data.

ToDo:

  • Download the TcAdsJavaScript.js_Sample02.zip
  • Start the PLC project
  • Copy the default.htm and TcAdsWebService.js to your cofigured virtual directory
  • Adjust NETID, PORT and SERVICE_URL if you use the TcAdsWebservice of a remote pc

<!DOCTYPE html>
<html>
<head>
    <title>TcAdsWebService.js Sample01</title>
    <script type="text/javascript" src="TcAdsWebService.js"></script>
    <script type="text/javascript">
        (function () {

            var NETID = ""; // Empty string for local machine;
            var PORT = "801"; // TC2 PLC Runtime = 801, TC3 PLC Runtime = 851
            var SERVICE_URL = "http://localhost/TcAdsWebService/TcAdsWebService.dll"; // HTTP path to the TcAdsWebService;

            var client = new TcAdsWebService.Client(SERVICE_URL, null, null);

            var general_timeout = 500;

            // Array of symbol names to read;
            var handlesVarNames = [
                    "MAIN.byteValue",
                    "MAIN.wordValue",
                    "MAIN.dwordValue",
                    "MAIN.sintValue",
                    "MAIN.intValue",
                    "MAIN.dintValue",
                    "MAIN.realValue",
                    "MAIN.lrealValue"
                ];

            var handlesVarSizes = [ 1, 2, 4, 1, 2, 4, 4, 8 ];

            var handles = [];

            // Occurs if the window has loaded;
            window.onload = (function () {

                // Register ui events
                btnWrite.onclick = BtnWriteClicked;

                // Create sumcommando for reading twincat symbol handles by symbol name;
                var handleswriter = new TcAdsWebService.DataWriter();

                // Write general information for each symbol handle to the TcAdsWebService.DataWriter object;
                for (var i = 0; i < handlesVarNames.length; i++) {
                    handleswriter.writeDINT(TcAdsWebService.TcAdsReservedIndexGroups.SymbolHandleByName);
                    handleswriter.writeDINT(0);
                    handleswriter.writeDINT(4); // Expected size; A handle has a size of 4 byte;
                    handleswriter.writeDINT(handlesVarNames[i].length); // The length of the symbol name string;
                }

                // Write symbol names after the general information to the TcAdsWebService.DataWriter object;
                for (var i = 0; i < handlesVarNames.length; i++) {
                    handleswriter.writeString(handlesVarNames[i]);
                }

                // Send the list-read-write command to the TcAdsWebService by use of the readwrite function of the TcAdsWebService.Client object;
                client.readwrite(
                    NETID,
                    PORT,
                    0xF082, 	// IndexGroup = ADS list-read-write command; Used to request handles for twincat symbols;
                    handlesVarNames.length, // IndexOffset = Count of requested symbol handles;
                    (handlesVarNames.length * 4) + (handlesVarNames.length * 8), // Length of requested data + 4 byte errorcode and 4 byte length per twincat symbol;
                    handleswriter.getBase64EncodedData(),
                    RequestHandlesCallback,
                    null,
                    general_timeout,
                    RequestHandlesTimeoutCallback,
                    true);

            });

            // Occurs if the readwrite for the sumcommando has finished;
            var RequestHandlesCallback = (function (e, s) {

                if (e && e.isBusy) {
                    // HANDLE PROGRESS TASKS HERE;
                    var message = "Requesting symbol handles...";
                    div_log.innerHTML = message;
                    // Exit callback function because request is still busy;
                    return;
                }

                if (e && !e.hasError) {

                    // Get TcAdsWebService.DataReader object from TcAdsWebService.Response object;
                    var reader = e.reader;

                    // Read error code and length for each handle;
                    for (var i = 0; i < handlesVarNames.length; i++) {

                        var err = reader.readDWORD();
                        var len = reader.readDWORD();

                        if (err != 0) {
                            div_log.innerHTML = "Symbol handle error!";
                            return;
                        }

                    }

                    var message = "Symbol handles successfully created!";
                    div_log.innerHTML = message;

                    // Read handles from TcAdsWebService.DataReader object;
                    handles[0] = reader.readDWORD();
                    handles[1] = reader.readDWORD();
                    handles[2] = reader.readDWORD();
                    handles[3] = reader.readDWORD();
                    handles[4] = reader.readDWORD();
                    handles[5] = reader.readDWORD();
                    handles[6] = reader.readDWORD();
                    handles[7] = reader.readDWORD();

                } else {

                    if (e.error.getTypeString() == "TcAdsWebService.ResquestError") {
                        // HANDLE TcAdsWebService.ResquestError HERE;
                        div_log.innerHTML = "Error: StatusText = " + e.error.statusText + " Status: " + e.error.status;
                    }
                    else if (e.error.getTypeString() == "TcAdsWebService.Error") {
                        // HANDLE TcAdsWebService.Error HERE;
                        div_log.innerHTML = "Error: ErrorMessage = " + e.error.errorMessage + " ErrorCode: " + e.error.errorCode;
                    }

                }

            });

            // Occurs if the readwrite for the sumcommando to request symbol handles runs into timeout;
            var RequestHandlesTimeoutCallback = (function () {
                // HANDLE TIMEOUT HERE;
                div_log.innerHTML = "Requuest symbol handles timeout!";
            });

              var BtnWriteClicked = (function () {

                // Create TcAdsWebService.DataWriter for write-read-write command.
                var writer = new TcAdsWebService.DataWriter();

                // Write general write-read-write commando information to TcAdsWebService.DataWriter object;
                var size = 0;
                for (var i = 0; i < handles.length; i++) {
                    writer.writeDINT(TcAdsWebService.TcAdsReservedIndexGroups.SymbolValueByHandle);
                    writer.writeDINT(handles[i]);
                    writer.writeDINT(handlesVarSizes[i]);

                    size = size + handlesVarSizes[i];
                }

                // Write values to TcAdsWebService.DataWrite object;
                writer.writeBYTE(parseFloat(Text1.value));
                writer.writeWORD(parseFloat(Text2.value));
                writer.writeDWORD(parseFloat(Text3.value));
                writer.writeSINT(parseFloat(Text4.value));
                writer.writeINT(parseFloat(Text5.value));
                writer.writeDINT(parseFloat(Text6.value));
                writer.writeREAL(parseFloat(Text7.value));
                writer.writeLREAL(parseFloat(Text8.value));

                client.readwrite(
                        NETID,
                        PORT,
                        0xF081, // 0xF081 = Call Write SumCommando
                        handles.length, // IndexOffset = Count of requested variables.
                        size+(handles.length*4), // Length of requested data + 4 byte errorcode per variable.
                        writer.getBase64EncodedData(),
                        WriteCallback,
                        null,
                        general_timeout,
                        WriteTimeoutCallback,
                        true);
            });

            var WriteCallback = (function(e,s){

                if (e && e.isBusy) {
                    // HANDLE PROGRESS TASKS HERE;
                    var message = "Writing data to plc...";
                    div_log.innerHTML = message;
                    // Exit callback function because request is still busy;
                    return;
                }

                if (e && !e.hasError) {

                    var message = "Writing data successfully finished...";
                    div_log.innerHTML = message;

                } else {

                    if (e.error.getTypeString() == "TcAdsWebService.ResquestError") {
                        // HANDLE TcAdsWebService.ResquestError HERE;
                        div_log.innerHTML = "Error: StatusText = " + e.error.statusText + " Status: " + e.error.status;
                    }
                    else if (e.error.getTypeString() == "TcAdsWebService.Error") {
                        // HANDLE TcAdsWebService.Error HERE;
                        div_log.innerHTML = "Error: ErrorMessage = " + e.error.errorMessage + " ErrorCode: " + e.error.errorCode;
                    }

                }
            });

            // Occurs if the write-read-write command runs into timeout;
            var WriteTimeoutCallback = (function () {
                // HANDLE TIMEOUT HERE;
                div_log.innerHTML = "Write timeout!";
            });

        })();
    </script>
</head>
<body>
    <h1>TcAdsWebService.js Sample02</h1>
    <h2>Write multiple variables with sumcommando!</h2>
    <table>
        <tr>
            <td>MAIN.byteValue:</td>
            <td><input id="Text1" type="text" /></td>
        </tr>
        <tr>
            <td>MAIN.wordValue:</td>
            <td><input id="Text2" type="text" /></td>
        </tr>
        <tr>
            <td>MAIN.dwordValue:</td>
            <td><input id="Text3" type="text" /></td>
        </tr>
        <tr>
            <td>MAIN.sintValue:</td>
            <td><input id="Text4" type="text" /></td>
        </tr>
        <tr>
            <td>MAIN.intValue:</td>
            <td><input id="Text5" type="text" /></td>
        </tr>
        <tr>
            <td>MAIN.dintValue:</td>
            <td><input id="Text6" type="text" /></td>
        </tr>
        <tr>
            <td>MAIN.realValue:</td>
            <td><input id="Text7" type="text" /></td>
        </tr>
        <tr>
            <td>MAIN.lrealValue:</td>
            <td><input id="Text8" type="text" /></td>
        </tr>
    </table>
    <input type="button" id="btnWrite" value="Write Values to PLC" />
    <div id="div_log"></div>
</body>
</html>


Sample Maschine.pro - HTML5, SVG, JavaScript

TwinCAT Quick Start

Example: Maschine.pro with HTML5, SVG, JavaScript

Web based standard technologies like HTML5, SVG (Scaleable Vector Graphics) and JavaScript are perfect for creating user interfaces which are platform independend and easy to deploy.

Required software:

  • HTML Editor
  • TwinCAT 2.11
  • TcAdsWebService
  • TcAdsWebService.js Library
  • Microsoft IIS (Internet Information Services) Webserver

Before you can start...

  • TwinCAT and the PLC program must be active.
  • Microsoft IIS has to be installed and configured for hosting the TcAdsWebService.

1. Creating the SVG for the user interface

Use a vector based design software of your choice to create the draft for the SVG user interface and make sure that all elements which you want to manipulate from JavaScript are named reasonable.

2. Creating the basic HTML5 document

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="X-UA-Compatible" content="IE=9" />
    <title>HTML5. SVG, JavaScript Machine Sample</title>
    <link rel="Stylesheet" href=StyleSheet.css />
    <script type="text/javascript" src="TcAdsWebService.js"></script>
    <script type="text/javascript">
    <!-- JavaScript will be placed here -->
    </script>
</head>
<body>
<!-- SVG will be placed here -->
</body>
</html>

This meta tag enables inline svg support for the Internet Explorer 9.
<meta http-equiv="X-UA-Compatible" content="IE=9" />

2. Implement the SVG code into the body of the HTML5 document

{...}
<body>
  <svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#"
       xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/"
       id="svgROOT" height="100%" width="100%" viewBox="0 0 800 600" version="1.1" style="display: block;">
    {...}
   </svg>
</body>
{...}

To grant the optimal displaying of the SVG user interface we have to add some additional information to the SVG root element.

  • The id is set to "svgROOT". This identifier can be used in JavaScript to get access to the SVG elements.
  • The "height" and "width" properties are set to 100% because we want the user interface to use all the available space in the browser.
  • The "viewBox" property defines the position and the original size of the SVG in the pattern "x-coordinate y-coordinate width height".
    Because of this, the SVG will only scale within its aspect ratio.

2. Implement the JavaScript based logic

Our code is created within a function which is called directly by the JavaScript interpreter to prevent from conflicts with other JavaScript elements which may exist later in this HTML document.

(function (window) {
    // We create our code here;
})(window);

At fist we define variables which exists in the whole context of our directly called JavaScript function.

var NETID = ""; // Empty string for local machine;
var PORT = "801"; // PLC Runtime port;
var SERVICE_URL = "http://" + window.document.location.hostname + "/TcAdsWebService/TcAdsWebService.dll"; // HTTP path to the target TcAdsWebService;

// The TcAdsWebService.Client object for ajax communication with the TcAdsWebService;
var client = new TcAdsWebService.Client(SERVICE_URL, null, null);

var general_timeout = 500; // This timeout value is used for all requests;

var readLoopID = null; // The id of the read interval; Can be used to stop the polling if need;
var readLoopDelay = 100;

var readSymbolValuesData = null; // This variable will store the Base64 encoded binary data string for the read sumcommando;

// Array of symbol names to read;
var handlesVarNames = [
        ".engine",
        ".deviceUp",
        ".deviceDown",
        ".steps",
        ".count",
        ".switch"
    ];

// Symbol handle variables;
var hEngine = null;
var hDeviceUp = null;
var hDeviceDown = null;
var hSteps = null;
var hCount = null;
var hSwitch = null;

// Base64 encoded binary data strings for write requests;
var switchTrueBase64 = null;
var switchFalseBase64 = null;

// UI Elements;
var radioActiveFast = null;
var radioActiveSlow = null;
var radioBackgroundFast = null;
var radioBackgroundSlow = null;
var textCount = null;
var upArrow = null;
var downArrow = null;
var progress = null;
var progressBackground = null;

var progress_initial_width = 0;

The initialization is done in the callback function of the window.onload event.
We do this, because we can be sure that all SVG and HTML elements do exist now.

window.onload = (function () { /* Initialization is done here */ });

Initializing

 // Initialize UI Elements;
radioActiveFast = svgROOT.getElementById("radioActiveFast");
radioActiveSlow = svgROOT.getElementById("radioActiveSlow");
radioBackgroundFast = svgROOT.getElementById("radioBackgroundFast");
radioBackgroundSlow = svgROOT.getElementById("radioBackgroundSlow");
textCount = svgROOT.getElementById("textCount");
upArrow = svgROOT.getElementById("UPArrow");
downArrow = svgROOT.getElementById("DownArrow");
progress = svgROOT.getElementById("progress");

progress_initial_width = progress.width.baseVal.value;

radioBackgroundFast.onclick = RadioBackgroundFastClick;
radioBackgroundSlow.onclick = RadioBackgroundSlowClick;

// Prepare data for writing to switch variable;
var switchTrueBase64Writer = new TcAdsWebService.DataWriter();
switchTrueBase64Writer.writeBOOL(true);
switchTrueBase64 = switchTrueBase64Writer.getBase64EncodedData();

var switchFalseBase64Writer = new TcAdsWebService.DataWriter();
switchFalseBase64Writer.writeBOOL(false);
switchFalseBase64 = switchFalseBase64Writer.getBase64EncodedData();

Now we initialize a TcAdsWebService.DataWriter object to create a Base64 encoded binary string which contains all the data which the sumcommando needs to request handles for the TwinCAT Symbol names in the "handlesVarNames" array.
With the "readwrite" function of the TcAdsWebService.Client object we start the sumcommando request against the TcAdsWebService.

 // Create sumcommando for reading twincat symbol handles by symbol name;
var handleswriter = new TcAdsWebService.DataWriter();

// Write general information for each symbol handle to the TcAdsWebService.DataWriter object;
for (var i = 0; i < handlesVarNames.length; i++) {
    handleswriter.writeDINT(TcAdsWebService.TcAdsReservedIndexGroups.SymbolHandleByName);
    handleswriter.writeDINT(0);
    handleswriter.writeDINT(4); // Expected size; A handle has a size of 4 byte;
    handleswriter.writeDINT(handlesVarNames[i].length); // The length of the symbol name string;
}

// Write symbol names after the general information to the TcAdsWebService.DataWriter object;
for (var i = 0; i < handlesVarNames.length; i++) {
    handleswriter.writeString(handlesVarNames[i]);
}

// Send the list-read-write command to the TcAdsWebService by use of the readwrite function of the TcAdsWebService.Client object;
client.readwrite(
    NETID,
    PORT,
    0xF082, // IndexGroup = ADS list-read-write command; Used to request handles for twincat symbols;
    handlesVarNames.length, // IndexOffset = Count of requested symbol handles;
    (handlesVarNames.length * 4) + (handlesVarNames.length * 8), // Length of requested data + 4 byte errorcode and 4 byte length per twincat symbol;
    handleswriter.getBase64EncodedData(),
    RequestHandlesCallback,
    null,
    general_timeout,
    RequestHandlesTimeoutCallback,
    true);

If the sumcommando to request the TwinCAT Symbol handles has finished, the RequestHandlesCallback function is called.
The parameter "e" will contain a TcAdsWebService.Response object with information about the request against the TcAdsWebService.
The parameter "s" is the "userState" parameter which was set to "null" in the function call.

// Occurs if the readwrite for the sumcommando has finished;
var RequestHandlesCallback = (function (e, s) {
    {...}
});

Within the RequestHandlesCallback function we collect the handle information from the TcAdsWebService.DataReader object in the "reader" property of the TcAdsWebService.Response object. With these handles we initialize another TcAdsWebService.DataWriter object with data for a read sumcommando which will be called cyclic in the ReadLoop function.

 if (e && e.isBusy) {
    // HANDLE PROGRESS TASKS HERE;
    // Exit callback function because request is still busy;
    return;
}

if (e && !e.hasError) {

    // Get TcAdsWebService.DataReader object from TcAdsWebService.Response object;
    var reader = e.reader;

    // Read error code and length for each handle;
    for (var i = 0; i < handlesVarNames.length; i++) {

        var err = reader.readDWORD();
        var len = reader.readDWORD();

        if (err != 0) {
            // HANDLE SUMCOMMANDO ERRORS HERE;
            return;
        }

    }

    // Read handles from TcAdsWebService.DataReader object;
    hEngine = reader.readDWORD();
    hDeviceUp = reader.readDWORD();
    hDeviceDown = reader.readDWORD();
    hSteps = reader.readDWORD();
    hCount = reader.readDWORD();
    hSwitch = reader.readDWORD();

    // Create sum commando to read symbol values based on the handle;
    var readSymbolValuesWriter = new TcAdsWebService.DataWriter();

    //  ".engine" // BOOL
    readSymbolValuesWriter.writeDINT(TcAdsWebService.TcAdsReservedIndexGroups.SymbolValueByHandle); // IndexGroup
    readSymbolValuesWriter.writeDINT(hEngine); // IndexOffset = The target handle
    readSymbolValuesWriter.writeDINT(1); // Size to read;

    //  ".deviceUp" // BOOL
    readSymbolValuesWriter.writeDINT(TcAdsWebService.TcAdsReservedIndexGroups.SymbolValueByHandle); // IndexGroup
    readSymbolValuesWriter.writeDINT(hDeviceUp); // IndexOffset = The target handle
    readSymbolValuesWriter.writeDINT(1); // Size to read;

    //  ".deviceDown" // BOOL
    readSymbolValuesWriter.writeDINT(TcAdsWebService.TcAdsReservedIndexGroups.SymbolValueByHandle); // IndexGroup
    readSymbolValuesWriter.writeDINT(hDeviceDown); // IndexOffset = The target handle
    readSymbolValuesWriter.writeDINT(1); // Size to read;

    //  ".steps" // BYTE
    readSymbolValuesWriter.writeDINT(TcAdsWebService.TcAdsReservedIndexGroups.SymbolValueByHandle); // IndexGroup
    readSymbolValuesWriter.writeDINT(hSteps); // IndexOffset = The target handle
    readSymbolValuesWriter.writeDINT(1); // Size to read;

    //  ".count" // UINT
    readSymbolValuesWriter.writeDINT(TcAdsWebService.TcAdsReservedIndexGroups.SymbolValueByHandle); // IndexGroup
    readSymbolValuesWriter.writeDINT(hCount); // IndexOffset = The target handle
    readSymbolValuesWriter.writeDINT(2); // Size to read;

    //  ".switch" // BOOL
    readSymbolValuesWriter.writeDINT(TcAdsWebService.TcAdsReservedIndexGroups.SymbolValueByHandle); // IndexGroup
    readSymbolValuesWriter.writeDINT(hSwitch); // IndexOffset = The target handle
    readSymbolValuesWriter.writeDINT(1); // Size to read;

    // Get Base64 encoded data from TcAdsWebService.DataWriter;
    readSymbolValuesData = readSymbolValuesWriter.getBase64EncodedData();

    // Start cyclic reading of symbol values;
    readLoopID = window.setInterval(ReadLoop, readLoopDelay);

    } else {

    if (e.error.getTypeString() == "TcAdsWebService.ResquestError") {
        // HANDLE TcAdsWebService.ResquestError HERE;
    }
    else if (e.error.getTypeString() == "TcAdsWebService.Error") {
        // HANDLE TcAdsWebService.Error HERE;
    }

}

The ReadLoop function calls the the read sumcommando on every tick;

// Interval callback for cyclic reading;
var ReadLoop = (function () {

    // Send the read-read-write command to the TcAdsWebService by use of the readwrite function of the TcAdsWebService.Client object;
    client.readwrite(
        NETID,
        PORT,
        0xF080, // 0xF080 = Read command;
        handlesVarNames.length, // IndexOffset = Variables count;
        7 + (handlesVarNames.length * 4), // Length of requested data + 4 byte errorcode per variable;
        readSymbolValuesData,
        ReadCallback,
        null,
        general_timeout,
        ReadTimeoutCallback,
        true);

});

In the ReadCallback function we collect the values of each TwinCAT Symbol in the TcAdsWebService.DataReader object of the "reader" porperty of the TcAdsWebService.Response object and use them to update the user interface.

// Occurs if the read-read-write command has finished;
var ReadCallback = (function (e, s) {

    if (e && e.isBusy) {
        // HANDLE PROGRESS TASKS HERE;
        // Exit callback function because request is still busy;
        return;
    }

    if (e && !e.hasError) {

        var reader = e.reader;

        // Read error codes from begin of TcAdsWebService.DataReader object;
        for (var i = 0; i < handlesVarNames.length; i++) {
            var err = reader.readDWORD();
            if (err != 0) {
                // HANDLE SUMCOMMANDO ERRORS HERE;
                return;
            }
        }

        // READ Symbol data from TcAdsWebService.DataReader object;
        //  ".engine" // BOOL
        var engine = reader.readBOOL();
        //  ".deviceUp" // BOOL
        var deviceUp = reader.readBOOL();
        //  ".deviceDown" // BOOL
        var deviceDown = reader.readBOOL();
        //  ".steps" // BYTE
        var steps = reader.readBYTE();
        //  ".count" // UINT/WORD
        var count = reader.readWORD();
        //  ".switch" // BOOL
        var switchVar = reader.readBYTE();

        // Update UI
        // Radio buttons
        if (switchVar) {
            radioActiveFast.style.visibility = "visible";
            radioActiveSlow.style.visibility = "hidden";
        } else {
            radioActiveFast.style.visibility = "hidden";
            radioActiveSlow.style.visibility = "visible";
        }

        // Textblock: Count
        textCount.textContent = "Count: " + count;

        // DeviceUp / DeviceDown Arrows
        if (deviceUp) {
            upArrow.style.fill = "#ea0000";
        } else {
            upArrow.style.fill = "#ffffff";
        }

        if (deviceDown) {
            downArrow.style.fill = "#ea0000";
        } else {
            downArrow.style.fill = "#ffffff";
        }

        // Progress
        var progress_scale = steps / 25; // 25 = max value of steps symbol;
        if (steps >= 0 && steps <= 25) {
            progress.width.baseVal.value = progress_initial_width * progress_scale;
        }
        else if (steps < 0) {
            progress.width.baseVal.value = 0.00;
        }
        else if (steps > 25) {
            progress.width.baseVal.value = progress_initial_width;
        }

    } else {

        if (e.error.getTypeString() == "TcAdsWebService.ResquestError") {
            // HANDLE TcAdsWebService.ResquestError HERE;
        }
        else if (e.error.getTypeString() == "TcAdsWebService.Error") {
            // HANDLE TcAdsWebService.Error HERE;
        }
    }

});

If the RadioBackgroundFastClick function or the RadioBackgroundSlowClick functions are called we send a "write" request with the specified Base64 encoded binary data against the TcAdsWebService.

// Occurs if the background of the radio button "Fast" is clicked;
var RadioBackgroundFastClick = (function () {

    client.write(
        NETID,
        PORT,
        0x0000F005, // IndexGroup = Write variable by handle;
        hSwitch,
        switchTrueBase64,
        RadioBackgroundFastWriteCallback,
        null,
        general_timeout,
        RadioBackgroundFastWriteTimeoutCallback,
        true
        );

});
// Occurs if the background of the radio button "Slow" is clicked;
var RadioBackgroundSlowClick = (function () {

    client.write(
        NETID,
        PORT,
        0x0000F005, // Write variable by handle;
        hSwitch,
        switchFalseBase64,
        RadioBackgroundSlowWriteCallback,
        null,
        general_timeout,
        RadioBackgroundSlowWriteTimeoutCallback,
        true
        );

});

If the browser window or the browser tab is going to be closed we release the used handles with the IndexGroup 0xF006 (Relase Symbol Handle).

window.onbeforeunload = (function () {

    // Free Handles
    client.write(NETID, PORT, 0xF006, hEngine, "", FreeHandleCallback, "hEngine", general_timeout, FreeHandleTimeoutCallback, true);
    client.write(NETID, PORT, 0xF006, hDeviceUp, "", FreeHandleCallback, "hDeviceUp", general_timeout, FreeHandleTimeoutCallback, true);
    client.write(NETID, PORT, 0xF006, hDeviceDown, "", FreeHandleCallback, "hDeviceDown", general_timeout, FreeHandleTimeoutCallback, true);
    client.write(NETID, PORT, 0xF006, hSteps, "", FreeHandleCallback, "hSteps", general_timeout, FreeHandleTimeoutCallback, true);
    client.write(NETID, PORT, 0xF006, hCount, "", FreeHandleCallback, "hCount", general_timeout, FreeHandleTimeoutCallback, true);
    client.write(NETID, PORT, 0xF006, hSwitch, "", FreeHandleCallback, "hSwitch", general_timeout, FreeHandleTimeoutCallback, true);

});

Now we can watch the Machine Sample in any Browser with HTML5 and inline SVG support.

2. Download the example

HTML5, SVG, JavaSript Example