Example 1: Expanded ADS function blocks
In the example application, READ-Requests are sent from a VB application to the PLC task in order to increment/decrement or reset a PLC counter variable. If successful the value of the counter variables is sent back to the VB application and outputted on the form. 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 required service in the PLC task is encoded in the index group parameter:
- IG:0x80000001 -> increment the counter variable;
- IG:0x80000002 -> decrement the counter variable;
- IG:0x80000003 -> set the counter variable = 0;
So that the requests can be routed to the PLC task, the highest value bit must be set in the index group parameter. The index offset parameter is zero.
Option Explicit
Dim tmpData(1) As Integer
Dim AdsResult As Integer
Private Sub Command1_Click()
AdsResult = AdsOcx1.AdsSyncReadReq(&H80000001, &H0, 2, tmpData)
Label1.Caption = "Ads result:" & AdsResult & " PLC data:" & tmpData(0)
End Sub
Private Sub Command2_Click()
AdsResult = AdsOcx1.AdsSyncReadReq(&H80000002, &H0, 2, tmpData)
Label1.Caption = "Ads result:" & AdsResult & " PLC data:" & tmpData(0)
End Sub
Private Sub Command3_Click()
AdsResult = AdsOcx1.AdsSyncReadReq(&H80000003, &H0, 2, tmpData)
Label1.Caption = "Ads result:" & AdsResult & " PLC data:" & tmpData(0)
End Sub
Private Sub Form_Load()
AdsOcx1.AdsAmsServerNetId = AdsOcx1.AdsAmsClientNetId
AdsOcx1.AdsAmsServerPort = 802 'PLC task number'
End Sub
The PLC program
The requests are intercepted as indications in the PLC task by an instance of the ADSREADIND function block. Next the index group and index offset parameters and the required data length and validity are checked. In the CASE instruction the desired operation is implemented on the PLC variables. If successful a response is sent back by an instance of the ADSREADRES function block to the caller with the current value of the PLC variables. In the case of an error an appropriate error message. At the end the CLEAR and RESPOND flags are reset in order to be able to process further indications.
PROGRAM MAIN
VAR
fbReadInd : ADSREADIND;(* Indication function block instance *)
fbReadRes : ADSREADRES;(* Response function block instance *)
sNetId : T_AmsNetID;
nPort : T_AmsPort;
nInvokeId : UDINT;
nIdxGrp : UDINT;
nIdxOffs : UDINT;
cbLength : UDINT;(* Requested read data/buffer byte size *)
cbRead : UDINT;(* Returned read data/buffer byte size *)
pRead : POINTER TO BYTE;(* Pointer to returned read data/buffer *)
nErrID : UDINT;(* Read indication result error code *)
nCounter : INT;(* Server data *)
END_VAR
fbReadRes( RESPOND := FALSE );(* Reset response function block *)
fbReadInd( CLEAR := FALSE );(* Trigger indication function block *)
IF fbReadInd.VALID THEN(* Check for new indication *)
sNetID := fbReadInd.NETID;
nPort := fbReadInd.PORT;
nInvokeID := fbReadInd.INVOKEID;
nIdxGrp := fbReadInd.IDXGRP;
nIdxOffs := fbReadInd.IDXOFFS;
cbLength := fbReadInd.LENGTH;
cbRead := 0;
pRead := 0;
nErrID := 16#701;(* ADS error: Service not supported by server *)
CASE nIdxGrp OF
(*------------------------------------------------------------------------------------*)
16#80000001:
CASE nIdxOffs OF
0:(* Increment counter value *)
IF cbLength >= SIZEOF(nCounter) THEN
nCounter := nCounter + 1;
cbRead := SIZEOF(nCounter);
pRead := ADR(nCounter);
nErrID := 0;
ELSE (* ADS error (example): Invalid size *)
nErrID := 16#705;
END_IF
ELSE (* ADS error (example): Invalid index offset *)
nErrID := 16#703;
END_CASE
(*------------------------------------------------------------------------------------*)
16#80000002:
CASE nIdxOffs OF
0:(* Decrement counter value *)
IF cbLength >= SIZEOF(nCounter) THEN
nCounter := nCounter - 1;
cbRead := SIZEOF(nCounter);
pRead := ADR(nCounter);
nErrID := 0;
ELSE(* ADS error (example): Invalid size *)
nErrID := 16#705;
END_IF
ELSE (* ADS error (example): Invalid index offset *)
nErrID := 16#703;
END_CASE
(*------------------------------------------------------------------------------------*)
16#80000003:
CASE nIdxOffs OF
0:(* Reset counter value *)
IF cbLength >= SIZEOF(nCounter) THEN
nCounter := 0;
cbRead := SIZEOF(nCounter);
pRead := ADR(nCounter);
nErrID := 0;
ELSE(* ADS error (example): Invalid size *)
nErrID := 16#705;
END_IF
ELSE (* ADS error (example): Service is not supported by server *)
nErrID := 16#701;(* ADS error: Service not supported *)
END_CASE
ELSE (* ADS error (example): Invalid index group *)
nErrID := 16#702;
END_CASE
fbReadRes( NETID := sNetID,
PORT := nPort,
INVOKEID := nInvokeID,
LEN := cbRead,
DATAADDR := pRead,
RESULT := nErrID,
RESPOND := TRUE );(* Send read response *)
fbReadInd( 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