Example 2: ADSWRITE Indication/Response

The VB application sends an array with 10 integer values to the PLC task of a BC9000 bus controller. In the PLC task of the bus controller, the data received should be copied into an array variable for further processing. The VB application uses ActiveX Control for communicating with the bus controller: AdsOcx. The bus controller must be entered as a remote PC in the TwinCAT system menu in order to be able to route the requests of the VB application to the bus controller via the Ethernet. Here you can unpack the complete sources relating to the sample application.

Entering BC9000 as remote PC in the TwinCAT system menu

Example 2: ADSWRITE Indication/Response 1:

The TwinCAT system menu can be accessed by clicking the TwinCAT icon->properties in the taskbar. Select Add in the AMS Router tab. Enter an arbitrary name for the remote PC in the dialog. The network address is entered in AMS Net Id. It consists of the IP address of the BC9000 and two further digits: "1.1". The IP address of the BC9000 is entered again in Address. The IP address must correspond to the address that was set via the dip switches on the bus controller. 

The VB application

Example 2: ADSWRITE Indication/Response 2:

 

A connection to the PLC task of the BC9000 Bus Controller is established in the Form_Load routine (port 800 and network address "172.16.17.63.1.1"). The first four digits of the network address correspond to the IP address of the bus controller. The desired service from the PLC task is encoded in the index group and index offset parameters. E.g.:

The VB application uses the AdsSyncWriteReq method to send 20 bytes of data to the bus controller. The values transmitted last are added to a list for monitoring purposes.  

Example 2: ADSWRITE Indication/Response 3:

So that the requests can be routed to the PLC task, the most significant bit must be set in the index group parameter. The values of the index group and index offset parameters can be freely defined. In our sample, the bus controller detects that it should copy the data received into an array via the index group and index offset parameters.

Option Explicit
    
Dim AdsResult     As Integer
Dim arrData(0 To 9)   As Integer

Private Sub cmdWrite_Click()
    Call List1.Clear
    
    Dim i As Long
    For i = LBound(arrData) To UBound(arrData)
    arrData(i) = arrData(i) + 1 'change values
    Call List1.AddItem("arrData(" & i & ") = " & arrData(i))
    Next i
    
    'calculate the byte length parameter
    Dim cbWriteSize As Long
    cbWriteSize = (UBound(arrData) - LBound(arrData) + 1) * LenB(arrData(LBound(arrData)))
    
    AdsResult = AdsOcx1.AdsSyncWriteReq(&H80000005, &H7, cbWriteSize, arrData) 'send data to PLC
    Label1.Caption = "Ads result: " & AdsResult
    
End Sub

Private Sub Form_Load()
    AdsOcx1.AdsAmsServerNetId =  "172.16.17.63.1.1"   
    AdsOcx1.AdsAmsServerPort = 800 'PLC task number of the BC9000 buscontroller'
    
    Dim i As Long
    For i = LBound(arrData) To UBound(arrData)
    arrData(i) = i    'init data
    Next i
End Sub

The PLC program

Create a new PLC project for the bus controller. The following PLC libraries for the bus controller must be integrated under library management: Standard.lb6, PlcHelperBC.lb6 and TcAdsBC.lb6. 

In the PLC task of the bus controller, an instance of the ADSWRITEIND function block is used to receive the data, and an instance of the ADSWRITERESBC function block is used to acknowledge receipt of the data. In the PLC task, the requests are intercepted as so-called indications by the ADSWRITEIND function block. The validity of the parameters index group and index offset and the transmitted data length is then checked for validity, and the data received are copied into an array variable. A response is then sent back to the caller from an instance of the ADSWRITERESBC function block (including an error code, if appropriate). This indicates to the VB application that the transmitted data were received successfully. 

Example 2: ADSWRITE Indication/Response 4:

With the rising edge at the CLEAR input of the ADSWRITEIND function block the address pointer to the most recently sent data becomes invalid ( == ZERO ). For this reason the sent data is first copied into the PLC variable before the CLEAR input is set to TRUE. At the end the CLEAR and RESPOND flags are reset in order to be able to process further indications.

PROGRAM MAIN
VAR
    fbWRITEIND              : ADSWRITEIND;
    fbWRITERESBC            : ADSWRITERESBC;

    szNetId             : STRING(23);
    Port                : UINT;
    InvokeId                : UDINT;
    idxGrp              : UDINT;
    idxOffs             : UDINT;
    cbLength                : UDINT;
    ErrorNumber             : UDINT;

    arrInt              : ARRAY[0..9] OF INT;
END_VAR

 

fbWRITEIND( );
fbWRITERESBC( );

IF ( fbWRITEIND.VALID ) THEN
    szNetId         := fbWRITEIND.NETID;
    Port        := fbWRITEIND.PORT;
    InvokeId        := fbWRITEIND.INVOKEID;
    idxGrp      := fbWRITEIND.IDXGRP;
    idxOffs         := fbWRITEIND.IDXOFFS;
    cbLength        := fbWRITEIND.LENGTH;
    ErrorNumber     := 0;


    CASE idxGrp OF
        16#80000005:

            CASE idxOffs OF
                16#00000007:
                    IF  cbLength <= SIZEOF( arrInt ) THEN
                        IF ( MEMCPY( ADR( arrInt ), fbWRITEIND.DATAADDR, UDINT_TO_INT(cbLength) ) =  0 ) THEN
                            ErrorNumber := 4000; (*MEMCPY fail*)
                        END_IF
                    ELSE
                        ErrorNumber := 1798;  (* ADS error: invalid parameter value(s)*)
                    END_IF
            ELSE
                ErrorNumber := 1795;    (*ADS error: Invalid index offset*)
            END_CASE

    ELSE
        ErrorNumber := 1794; (*ADS error: invalid index group*)
    END_CASE


    fbWRITEIND(  CLEAR := TRUE );       (*clear indication entry*)


    fbWRITERESBC.NETID := szNetId;
    fbWRITERESBC.PORT := Port;
    fbWRITERESBC.INVOKEID := InvokeId;
    fbWRITERESBC.RESULT := ErrorNumber;
    fbWRITERESBC( RESPOND :=  TRUE );       (*send response*)

END_IF

(*reset fb's*)
IF NOT fbWRITERESBC.BUSY THEN
    fbWRITEIND( CLEAR := FALSE );
    fbWRITERESBC( RESPOND := FALSE );
END_IF

Here you can unpack the complete sources for the sample application: sample application with the extended ADS function blocks