Example 2: Expanded ADS function blocks
The VB application sends an array containing integer values to a PLC task. The most recently sent values are added to a list, and are copied into a corresponding array variable in the PLC. The VB application uses a WRITE request to send the data. The ADSWRITEIND function block is used in the PLC in order to receive the data, while the ADSWRITERES function block is used to acknowledge the WRITE request. In order to communicate with the PLC task the VB application uses the ActiveX control: AdsOcx.

Here you can unpack the complete sources relating to the example application: Example application with the expanded ADS function blocks
The VB application
A connection to the PLC task is constructed in the Form_Load-Routine (port 802 on the local computer). 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.
So that the requests can be routed to the PLC task, the highest value bit must be set in the index group parameter.
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 = AdsOcx1.AdsAmsClientNetId
AdsOcx1.AdsAmsServerPort = 802 'PLC task number'
Dim i As Long
For i = LBound(arrData) To UBound(arrData)
arrData(i) = i 'init data
Next i
End Sub
The PLC program
The requests are intercepted as indications in the PLC task by an instance of the ADSWRITEIND function block. Following this, the index group, index offset and transmitted data length parameters are checked for validity, and the desired operation is carried out on the PLC variable. The next step is for a response to be returned to the caller (including an error code, if appropriate) by an instance of the ADSWRITERES function block. At the end the CLEAR and RESPOND flags are reset in order to be able to process further indications.
![]() | With the rising edge at the CLEAR input of the ADSWRITEIND function block the address pointer to the most recently sent data becomes invalid ( == NULL ). For this reason the sent data is first copied into the PLC variable before the CLEAR input is set to TRUE. |
PROGRAM MAIN
VAR
fbWriteInd : ADSWRITEIND;
fbWriteRes : ADSWRITERES;
sNetId : T_AmsNetID;
nPort : T_AmsPort;
nInvokeId : UDINT;
nIdxGrp : UDINT;
nIdxOffs : UDINT;
cbWrite : UDINT;(* Byte size of written data *)
pWrite : POINTER TO BYTE;(* Pointer to written data buffer *)
nResult : UDINT;(* Write indication result error code *)
arrInt : ARRAY[0..9] OF INT;(* Server data *)
END_VAR
fbWriteRes( RESPOND := FALSE );(* Reset response function block *)
fbWriteInd( CLEAR := FALSE );(* Trigger indication function block *)
IF ( fbWriteInd.VALID ) THEN
sNetId := fbWriteInd.NETID;
nPort := fbWriteInd.PORT;
nInvokeId := fbWriteInd.INVOKEID;
nIdxGrp := fbWriteInd.IDXGRP;
nIdxOffs := fbWriteInd.IDXOFFS;
cbWrite := fbWriteInd.LENGTH;
pWrite := fbWriteInd.DATAADDR;
nResult := 16#701;(* ADS error: Service not supported by server *)
CASE nIdxGrp OF
16#80000005:
CASE nIdxOffs OF
16#00000007:
IF cbWrite <= SIZEOF( arrInt ) THEN
MEMCPY( ADR( arrInt ), pWrite, MIN( cbWrite, SIZEOF(arrInt) ) );
nResult := 0;
ELSE(* ADS error (example): Invalid size *)
nResult := 16#705;
END_IF
ELSE(* ADS error (example): Invalid index offset *)
nResult := 16#703;
END_CASE
ELSE(* ADS error (example): Invalid index group *)
nResult := 16#702;
END_CASE
fbWriteRes( NETID := sNetId,
PORT := nPort,
INVOKEID := nInvokeId,
RESULT := nResult,
RESPOND := TRUE ); (* Send write response *)
fbWriteInd( CLEAR := TRUE ); (* Clear indication entry *)
END_IF
Here you can unpack the complete sources relating to the example application: Example application with the expanded ADS function blocks