Statusänderung vom TwinCAT-Router und der SPS erkennen

Zur Laufzeit einer Applikation ist es oft von Bedeutung, den Status von TwinCAT und/oder dessen Komponenten abzufragen; z. B. ob die SPS im RUN-Status ist. Damit dieses nicht ständig abgefragt werden muß, kann mit Hilfe von Callback-Funktionen eine Statusänderung auf sehr effektive Weise erkannt werden.
Mit dem folgenden Beispielprogramm wird der Status der SPS (Laufzeitsystem 1) und der des TwinCAT-Routers überwacht.
Durch den Aufruf der Funktion AdsAmsRegisterRouterNotification() wird bei jeder Statusänderung des TwinCAT-Routers die angegebende Callback-Funktion aufgerufen. Anhand des Parameters, der übergeben wird, kann der aktuelle Status abgefragt werden.
Mit Hilfe der Funktion AdsSyncAddDeviceNotificationReq() wird der Status der SPS überwacht. Die Daten, die an die Callback-Funktion übergeben werden, stellen der aktuellen Status der SPS da.

Download: sample11-c-ads-dll-detectstatuschanges.zip

#include <iostream.h>
#include <conio.h>
#include <windows.h>
#include <winbase.h>

// ADS headers
#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: TwinCAT2 PLC1
  pAddr->port = 801;
 
  nErr = AdsAmsRegisterRouterNotification(&RouterCall);
  if (nErr) cerr << "Error: AdsAmsRegisterRouterNotification: " << nErr << '\n';

  // Invoke notification
  adsNotificationAttrib.cbLength       = sizeof(short);
  adsNotificationAttrib.nTransMode     = ADSTRANS_SERVERONCHA;
  adsNotificationAttrib.nMaxDelay      = 0; // report each change directly
  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 ();
}