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
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
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.:
- IG:0x80000005 and
- IO:0x00000007-> Copy the sent data into the array in the PLC.
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.
![]() | 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.
![]() | 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