Detect status change in TwinCAT router and the PLC

Download: 'Detect status change in TwinCAT router and the PLC'

When an application is actually running it is often important to interrogate the status of TwinCAT and/or of its components; e.g., whether the PLC is in the RUN state. To avoid the need to repeatedly issue this inquiry, changes in the status can be detected very effectively with the aid of callback functions.
The following example program monitors the status of the PLC (run-time system 1) and of the TwinCAT router.
By invoking the AdsAmsRegisterRouterNotification() function, the given callback function will be invoked every time the status of the TwinCAT router changes. The current status can be interrogated by means of the parameters that are transferred.
The AdsSyncAddDeviceNotificationReq() is used to monitor the status of the PLC. The data that is passed to the callback function represents the current status of the PLC.

#include <iostream.h>
#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"

void __stdcall Callback(AmsAddr*, AdsNotificationHeader*, ULONG);
void __stdcall RouterCall(LONG);

void main()
{
LONG nErr, nPort;
ULONG hNotification, hUser = 0;
AmsAddr Addr;
PAmsAddr pAddr = &Addr;
AdsNotificationAttrib adsNotificationAttrib;

// Open communication port on the ADS router
nPort = AdsPortOpen();
nErr = AdsGetLocalAddress(pAddr);
if (nErr) cerr << "Error: AdsGetLocalAddress: " << nErr << '\n';

// Select Port: TwinCAT 3 PLC1 = 851
pAddr->port = 851;

nErr = AdsAmsRegisterRouterNotification(&RouterCall);
if (nErr) cerr << "Error: AdsAmsRegisterRouterNotification: " << nErr << '\n';

// Invoke notification
adsNotificationAttrib.cbLength = sizeof(short);
adsNotificationAttrib.nTransMode = ADSTRANS_SERVERONCHA;
adsNotificationAttrib.nMaxDelay = 0; // jede Aenderung sofort melden
adsNotificationAttrib.dwChangeFilter = 0; //
nErr = AdsSyncAddDeviceNotificationReq(pAddr, ADSIGRP_DEVICE_DATA, ADSIOFFS_DEVDATA_ADSSTATE, &adsNotificationAttrib, Callback, hUser, &hNotification);
if (nErr) cerr << "Error: AdsSyncAddDeviceNotificationReq: " << nErr << "\n";
getch();

// The following calls return errors if TwinCAT is halted
nErr = AdsSyncDelDeviceNotificationReq(pAddr, hNotification);
if (nErr) cerr << "Error: AdsSyncDelDeviceNotificationReq: " << nErr << '\n';

nErr = AdsAmsUnRegisterRouterNotification();
if (nErr) cerr << "Error: AdsAmsUnRegisterRouterNotification: " << nErr << '\n';

nErr = AdsPortClose();
if (nErr) cerr << "Error: AdsPortClose: " << nErr << '\n';

return;
}

// ADS state callback function
void __stdcall Callback(AmsAddr* pAddr, AdsNotificationHeader* pNotification, ULONG hUser)
{
INT nIndex;
nIndex = *(short *)pNotification->data;
switch (nIndex)
{
case ADSSTATE_RUN:
cout << "PLC run\n";
break;
case ADSSTATE_STOP:
cout << "PLC stop\n";
break;
default :
cout << "PLC ADS-State" << nIndex << "\n";
break;
}
cout.flush ();
}

// TwinCAT router callback function
void __stdcall RouterCall (long nReason)
{
switch (nReason)
{
case AMSEVENT_ROUTERSTOP:
cout << "TwinCAT-Router stop\n";
break;
case AMSEVENT_ROUTERSTART:
cout << "TwinCAT-Router start\n";
break;
case AMSEVENT_ROUTERREMOVED:
cout << "TwinCAT-Router removed\n";
break;
default:
cout << "TwinCAT-Router AMS-Event " << nReason << "\n";
break;
}
cout.flush ();
}