Event driven reading
Download: 'Event driven reading'
If values from a PLC or NC are to be displayed continuously on a user interface, then it is very inefficient to use AdsSyncReadReq(), since this function must be called cyclically. By defining what are known as notifications (messages), a TwinCAT server can be made to transmit values via ADS to another ADS device. A distinction is drawn between whether the TwinCAT server is to transmit the values cyclically, or only when the values change.
A notification is begun with the AdsSyncAddDeviceNotificationReq() function. After this, the callback function is automatically invoked by TwinCAT. AdsSyncDelDeviceNotificationReq() is used to halt the notification again. Since the number of notifications is limited, you should ensure the notifications no longer required by your program are deleted. You will find further information under the description of the AdsNotificationAttrib structure.
The following program starts a notification on a variable handle in the PLC. Each time the PLC variable changes, the callback function is invoked. The callback function receives a variable of type AdsNotificationHeader() as one of its parameters. This structure contains all the necessary information (value, time stamp, ...).
![]() | Efficient Usage
|
#include <iostream>
#include <conio.h>
#include <windows.h>
#include <winbase.h>
// ADS headers for TwinCAT 3
#include "C:\TwinCAT\AdsApi\TcAdsDll\Include\TcAdsDef.h"
#include "C:\TwinCAT\AdsApi\TcAdsDll\Include\TcAdsAPI.h"
using namespace std;
void _stdcall Callback(AmsAddr*, AdsNotificationHeader*, unsigned long);
void main()
{
long nErr, nPort;
AmsAddr Addr;
PAmsAddr pAddr = &Addr;
ULONG hNotification, hUser;
AdsNotificationAttrib adsNotificationAttrib;
char szVar []={"MAIN.PLCVar"};
// open communication port on the ADS router
nPort = AdsPortOpen();
nErr = AdsGetLocalAddress(pAddr);
if (nErr) cerr << "Error: AdsGetLocalAddress: " << nErr << '\n';
// TwinCAT 3 RTS1 Port = 851
pAddr->port = 851;
// set the attributes of the notification
adsNotificationAttrib.cbLength = 4;
adsNotificationAttrib.nTransMode = ADSTRANS_SERVERONCHA;
adsNotificationAttrib.nMaxDelay = 0;
adsNotificationAttrib.nCycleTime = 10000000; // 1sec
// get handle
nErr = AdsSyncReadWriteReq(pAddr, ADSIGRP_SYM_HNDBYNAME, 0x0, sizeof(hUser), &hUser, sizeof(szVar), szVar);
if (nErr) cerr << "Error: AdsSyncReadWriteReq: " << nErr << '\n';
// initiate the transmission of the PLC-variable
nErr = AdsSyncAddDeviceNotificationReq(pAddr, ADSIGRP_SYM_VALBYHND, hUser, &adsNotificationAttrib, Callback, hUser, &hNotification);
if (nErr) cerr << "Error: AdsSyncAddDeviceNotificationReq: " << nErr << '\n';
cout << "Notification: " << hNotification << "\n\n";
cout.flush();
// wait for user intraction (keystroke)
getch();
// finish the transmission of the PLC-variable
nErr = AdsSyncDelDeviceNotificationReq(pAddr, hNotification);
if (nErr) cerr << "Error: AdsSyncDelDeviceNotificationReq: " << nErr << '\n';
// release handle
nErr = AdsSyncWriteReq(pAddr, ADSIGRP_SYM_RELEASEHND, 0, sizeof(hUser), &hUser);
if (nErr) cerr << "Error: AdsSyncWriteReq: " << nErr << '\n';
// Close the communication port
nErr = AdsPortClose();
if (nErr) cerr << "Error: AdsPortClose: " << nErr << '\n';
}
// Callback-function
void __stdcall Callback(AmsAddr* pAddr, AdsNotificationHeader* pNotification, ULONG hUser)
{
int nIndex;
static ULONG nCount = 0;
SYSTEMTIME SystemTime, LocalTime;
FILETIME FileTime;
LARGE_INTEGER LargeInteger;
TIME_ZONE_INFORMATION TimeZoneInformation;
cout << ++nCount << ". Call:\n";
// print (to screen)) the value of the variable
cout << "Value: " << *(ULONG *)pNotification->data << '\n';
cout << "Notification: " << pNotification->hNotification << '\n';
// Convert the timestamp into SYSTEMTIME
LargeInteger.QuadPart = pNotification->nTimeStamp;
FileTime.dwLowDateTime = (DWORD)LargeInteger.LowPart;
FileTime.dwHighDateTime = (DWORD)LargeInteger.HighPart;
FileTimeToSystemTime(&FileTime, &SystemTime);
// Convert the time value Zeit to local time
GetTimeZoneInformation(&TimeZoneInformation);
SystemTimeToTzSpecificLocalTime(&TimeZoneInformation, &SystemTime, &LocalTime);
// print out the timestamp
cout << LocalTime.wHour << ":" << LocalTime.wMinute << ":" << LocalTime.wSecond << '.' << LocalTime.wMilliseconds <<
" den: " << LocalTime.wDay << '.' << LocalTime.wMonth << '.' << LocalTime.wYear << '\n';
// Größe des Buffers in Byte
cout << "SampleSize: " << pNotification->cbSampleSize << '\n';
// 32-Bit Variable (auch Zeiger), die beim AddNotification gesetzt wurde // (siehe main)
cout << "hUser: " << hUser << '\n';
// Print out the ADS-address of the sender
cout << "ServerNetId: ";
for (nIndex = 0; nIndex < 6; nIndex++)
cout << (int)pAddr->netId.b[nIndex] << ".";
cout << "\nPort: " << pAddr->port << "\n\n";
cout.flush();
}