Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Migration of unmigrated content due to installation of a new plugin

Ads funktioiden avulla voi toteuttaa kättetelyn kättelyn c++ ohjelman ja Beckhoffin logikan logiikan välillä.

Yksinkertainen esimerkki

Code Block
titleWindow määrittelyjä
collapsetrue
#ifndef WINTYPES_H
#define WINTYPES_H

/*
Microsoftin tytöt ja pojat ovat halunneet keksiä omia nimiä standardi cpp:n tyypeille,
alla muutamia tärkeimpiä, joita tässä esimerkissä tarvitaan. Saatat tarvita Windows projektissa lisää tyyppejä. Niitä löydät osoitteesta
http://msdn.microsoft.com/en-us/library/aa383751(VS.85).aspx#BYTE
*/
typedef int INT;
typedef char* LPSTR;
#define WINAPI __stdcall
typedef int BOOL;
typedef BOOL *PBOOL;
typedef void VOID;
#define CALLBACK __stdcall
typedef unsigned long DWORD;
typedef DWORD *PDWORD;
typedef char CHAR;
typedef CHAR *PCHAR;
typedef float FLOAT;
typedef FLOAT *PFLOAT;
typedef unsigned short WORD;
typedef WORD *PWORD;
typedef short SHORT;
typedef SHORT PSHORT;
typedef void *PVOID;
typedef unsigned char BYTE;
typedef BYTE *PBYTE;
typedef  int   DaqHandleT;
typedef unsigned long ULONG;
typedef long LONG;
typedef unsigned int UINT;
typedef unsigned short USHORT;
typedef wchar_t WCHAR;
typedef unsigned long ULONG;
#endif // WINTYPES_H

...

Code Block

...

title
Esimerkkejä

ADS-DLL Sample01.zip

ADS-DLL Sample02.zip

ADS-DLL Sample03.zip

ADS-DLL Sample04.zip

 

BechoffEsim.zip

projektitiedostoon kirjaston polku
collapsetrue
LIBS += "c://twincat//AdsApi//tcadsdll//lib//TcAdsDll.lib"
Code Block
titleotsikkotiedosto
collapsetrue
#ifndef DIALOG_H
#define DIALOG_H
#include <QDialog>
#include "WinTypes.h"
#include "c:\twincat\AdsApi\tcadsdll\include\tcadsdef.h"
#include "c:\twincat\AdsApi\tcadsdll\include\tcadsapi.h"

namespace Ui {
class Dialog;
}
class Dialog : public QDialog
{
    Q_OBJECT
public:
    explicit Dialog(QWidget *parent = 0);
    ~Dialog();
    long     nErr, nPort;
    AmsAddr  Addr;
    PAmsAddr pAddr;
    DWORD    dwData;
    ULONG hAnalogInputs;
    ULONG hAnalogOutputs;
    void WriteDataToLogic(qint32 *asetusarvot, quint8 kokoTavuina);
    void ReadDataFromLogic(qint32 *mitatutArvot, quint32 kokoTavuina);
private:
    Ui::Dialog *ui;
};
#endif // DIALOG_H
Code Block
titleluokan funktiot
collapsetrue
#include "dialog.h"
#include "ui_dialog.h"


Dialog::Dialog(QWidget *parent) :QDialog(parent),ui(new Ui::Dialog)
{
    ui->setupUi(this);
    pAddr = &Addr;
    nPort = AdsPortOpen();
    nErr = AdsGetLocalAddress(pAddr);
    pAddr->port =851;
    //5.11.25.80.1.1 netid on logiikan identiteetti (jokaisella oma)
    pAddr->netId.b[0]=5;
    pAddr->netId.b[1]=11;
    pAddr->netId.b[2]=25;
    pAddr->netId.b[3]=80;
    pAddr->netId.b[4]=1;
    pAddr->netId.b[5]=1;
    nErr=AdsSyncReadWriteReq( pAddr, ADSIGRP_SYM_HNDBYNAME, 0x0, 
                              sizeof(ULONG), &hAnalogInputs,
                              sizeof("MAIN.communication.AnalogInputsToPc_"),
                              "MAIN.communication.AnalogInputsToPc_");
...

}


Dialog::~Dialog()
{
    delete ui;
}

void Dialog::WriteDataToLogic(qint32 *asetusarvot, quint8 kokoTavuina)
{
    nErr=AdsSyncWriteReq( pAddr, ADSIGRP_SYM_VALBYHND, hAnalogOutputs,kokoTavuina,asetusarvot);
    Q_ASSERT(nErr==0);
}

void Dialog::ReadDataFromLogic(qint32 *mitatutArvot, quint32 kokoTavuina)
{
    nErr=AdsSyncReadReq( pAddr, ADSIGRP_SYM_VALBYHND,hAnalogInputs, lengthOfVectorAsBytes,mitatutArvot);
    Q_ASSERT(nErr==0);
}

 

Esimerkkejä

ADS-DLL Sample01.zip

ADS-DLL Sample02.zip

ADS-DLL Sample03.zip

ADS-DLL Sample04.zip

 

BechoffEsim.zip

 

 

Code Block#include "beckhoff.h" //variables of callback functions ULONG nCount; SYSTEMTIME SystemTime, LocalTime; FILETIME FileTime; LARGE_INTEGER LargeInteger; TIME_ZONE_INFORMATION TimeZoneInformation; unsigned long pNotificationData; unsigned long pNotificationHNotification; unsigned long pNotificationCbSampleSize; unsigned long huser; unsigned int b[10]; unsigned short portt[10]; Beckhoff::Beckhoff(QObject *parent) : QObject(parent) { } // Callback function void __stdcall EventsInPlc(AmsAddr* pAddr, AdsNotificationHeader* pNotification, ULONG hUser) { int nIndex; ++nCount; // Output value of the variable //cout << "Value: " << *(ULONG *)pNotification->data << '\n'; //cout << "Notification: " << pNotification->hNotification << '\n'; pNotificationData= *(ULONG *)pNotification->data; pNotificationHNotification= pNotification->hNotification; // Convert time stamp to SYSTEMTIME LargeInteger.QuadPart = pNotification->nTimeStamp; FileTime.dwLowDateTime = (DWORD)LargeInteger.LowPart; FileTime.dwHighDateTime = (DWORD)LargeInteger.HighPart; //aikafunktiot eivat toimi // FileTimeToSystemTime(&FileTime, &SystemTime); // Calculate time in local representation // GetTimeZoneInformation(&TimeZoneInformation); // SystemTimeToTzSpecificLocalTime(&TimeZoneInformation, &SystemTime, &LocalTime); // Output time stamp //cout << LocalTime.wHour << ":" << LocalTime.wMinute << ":" << LocalTime.wSecond << '.' << LocalTime.wMilliseconds << // " den: " << LocalTime.wDay << '.' << LocalTime.wMonth << '.' << LocalTime.wYear << '\n'; // Size of buffer in bytes //cout << "SampleSize: " << pNotification->cbSampleSize << '\n'; pNotificationCbSampleSize=pNotification->cbSampleSize; // 32-bit variable (including pointers) that are set by AddNotification // (See main) // cout << "hUser: " << hUser << '\n'; huser=hUser; // Output ADS address of the sender //cout << "ServerNetId: "; for (nIndex = 0; nIndex < 6; nIndex++){ b[nIndex]=(int)pAddr->netId.b[nIndex] ; portt[nIndex]= pAddr->port; } //cout.flush(); } // TwinCAT router callback function void __stdcall RouterCall (long nReason) { switch (nReason) { case AMSEVENT_ROUTERSTOP: qDebug()<< "TwinCAT-Router stop"; break; case AMSEVENT_ROUTERSTART: qDebug()<< "TwinCAT-Router start"; break; case AMSEVENT_ROUTERREMOVED: qDebug()<< "TwinCAT-Router removed"; break; default: QString tmp1; tmp1.setNum(nReason); qDebug()<< "TwinCAT-Router AMS-Event " << tmp1; break; } } // ADS state callback function void __stdcall ADS_StateCallback(AmsAddr* pAddr, AdsNotificationHeader* pNotification, ULONG hUser) { INT nIndex; nIndex = *(short *)pNotification->data; switch (nIndex) { case ADSSTATE_RUN: qDebug()<< "PLC run"; break; case ADSSTATE_STOP: qDebug()<< "PLC stop"; break; default : QString tmp1; tmp1.setNum(nIndex); qDebug()<< "PLC ADS-State" << tmp1; break; } } //!Read DLL version /*! This program determines the version of the DLL file. */ void Beckhoff::ReadDLLversion() { long nTemp; AdsVersion* pDLLVersion; QString tmp1,tmp2; nTemp = AdsGetDllVersion(); pDLLVersion = (AdsVersion *)&nTemp; tmp1.setNum((int)pDLLVersion->version); tmp2="versio="; tmp2+=tmp1; tmp2+=" revision="; tmp1.setNum((int)pDLLVersion->revision); tmp2+=tmp1; tmp2+=" build="; tmp1.setNum((int)pDLLVersion->build); tmp2+=tmp1; ansver=tmp2; emit OkMessage(ansver); // emit Errors(ansver); } //! Write flag synchronously into the PLC int Beckhoff::WriteFlagSynchronouslyIntoThePLC() { LONG nErr, nPort; //ULONG hNotification, hUser = 0; //AdsNotificationAttrib adsNotificationAttrib; pAddr = &Addr; // Open communication port on the ADS router nPort = AdsPortOpen(); nErr = AdsGetLocalAddress(pAddr); if(nErr){ emit Errors("Not local address found"); return -1; } pAddr->port = AMSPORT_R0_PLC_RTS1;//mika tama on? // Write value to MD0 mika MDO?? nErr = AdsSyncWriteReq( pAddr, 0x4020, 0x0, 0x4, &dwData );//mita ovat parametrit if (nErr){ emit Errors("ads sync writing not succeed"); return -2;} // Close communication port nErr = AdsPortClose(); if (nErr){ emit Errors("ads can not close port"); return -3; } } //! Read flag synchronously from the PLC /*! In this example program the value in flag double word 0 in the PLC is read and displayed on the screen. */ int Beckhoff::ReadFlagSynchronouslyFromThePLC() { long nErr, nPort; pAddr = &Addr; int i=0; // Open communication port on the ADS router nPort = AdsPortOpen(); nErr = AdsGetLocalAddress(pAddr); if (nErr){ tmp.setNum(nErr); tmp1+="Error: AdsGetLocalAddress: "; tmp1+= tmp; emit Errors(tmp1); } pAddr->port = AMSPORT_R0_PLC_RTS1; // Read value from MD0 and display do { i++; nErr = AdsSyncReadReq(pAddr, 0x4020, 0x0, 0x4, &dwData); if (nErr){ tmp= "Error: AdsSyncReadReq: "; tmp1.setNum(nErr); tmp+=tmp1; tmp1.setNum(dwData); tmp+=" "; tmp+=tmp1; emit Errors(tmp); tmp.setNum(dwData); tmp+=" "; emit SendData(tmp); } } while (i<10);//getch() == '\r'); // Read the next value (use Carriage return as delimitter), stop otherwise // Close communication port nErr = AdsPortClose(); if (nErr){ tmp= "Error: AdsPortClose: "; tmp1.setNum(nErr); tmp+=tmp1; emit Errors(tmp); } return 1; } //! Read ADS status /*! This program reads the status of the PLC. The variable of type ADSSTATE which contains information such as, for example, whether the PLC is in the RUN or STOP state. */ int Beckhoff::ReadAdsStatus() { //ADSSTATE mikähän mättä kun ei voi käyttää alla unsigned short nAdsState; USHORT nDeviceState; pAddr = &Addr; nPort = AdsPortOpen();// Open communication port on the ADS router nErr = AdsGetLocalAddress(pAddr); if (nErr){ tmp1.setNum(nErr); tmp="Error: AdsGetLocalAddress: " ; tmp+=tmp1; emit Errors(tmp); return -1; } pAddr->port = AMSPORT_R0_PLC_RTS1; // do // { nErr = AdsSyncReadStateReq(pAddr, &nAdsState, &nDeviceState); if (nErr){ tmp1.setNum(nErr); tmp="Error: AdsSyncReadStateReq: " ; tmp+=tmp1; emit Errors(tmp); } else{ tmp= "AdsState: "; tmp1.setNum(nAdsState); tmp+=tmp1; tmp+= "DeviceState: "; tmp1.setNum( nDeviceState); tmp+=tmp1; emit OkMessage("message ok"); emit SendData(tmp); } // } //while ( getch() == '\r'); // continue on a carriage return, finish for any other key nErr = AdsPortClose();// Close communication port if (nErr){ tmp= "Error: AdsPortClose: "; tmp1.setNum(nErr); tmp+=tmp1; emit Errors(tmp); return -1; } return 1; } //! Read ADS information /*! Each ADS device contains a version number and an identification. The example program reads this information from the PLC and displays it on the screen. */ int Beckhoff::ReadAdsInformation() { LONG nErr, nPort; AdsVersion Version; AdsVersion *pVersion = &Version; char pDevName[50]; pAddr = &Addr; nPort = AdsPortOpen();// Open communication port on the ADS router nErr = AdsGetLocalAddress(pAddr); if (nErr){ tmp1.setNum(nErr); tmp="Error: AdsGetLocalAddress: " ; tmp+=tmp1; emit Errors(tmp); } pAddr->port = AMSPORT_R0_PLC_RTS1; nErr = AdsSyncReadDeviceInfoReq(pAddr, pDevName, pVersion); if (nErr){ tmp1.setNum(nErr); tmp="Error: AdsSyncReadDeviceInfoReq: " ; tmp+=tmp1; emit Errors(tmp); } else{ tmp1.sprintf("%s",pDevName); tmp= "Name: "; tmp+=tmp1; tmp+="Version: "; tmp1.setNum((int)pVersion->version); tmp+=tmp1; tmp+="Revision: "; tmp1.setNum((int)pVersion->revision); tmp+="Build: "; tmp1.setNum(pVersion->build); tmp+=tmp1; emit OkMessage(tmp); } // Close communication port nErr = AdsPortClose();// Close communication port if (nErr){ tmp= "Error: AdsPortClose: "; tmp1.setNum(nErr); tmp+=tmp1; emit Errors(tmp); return -1; } } //! Start/stop PLC /*! The following program starts or stops run-time system 1 in the PLC. */ int Beckhoff::StartStopPlc(bool start) { USHORT nAdsState; USHORT nDeviceState = 0; long nErr, nPort; int ch; void *pData = NULL; //AmsAddr Addr; pAddr = &Addr; // Open communication port on the ADS router nPort = AdsPortOpen(); nErr = AdsGetLocalAddress(pAddr); if (nErr){ tmp="Error: AdsGetLocalAddress: "; tmp1.setNum(nErr); tmp+=tmp1; emit Errors(tmp); return -1; } pAddr->port = AMSPORT_R0_PLC_RTS1; if(start==true){ nAdsState = ADSSTATE_RUN; } else{ nAdsState = ADSSTATE_STOP; } nErr = AdsSyncWriteControlReq (pAddr, nAdsState, nDeviceState, 0, pData); if (nErr){ tmp="Error: AdsSyncWriteControlReq: "; tmp1.setNum(nErr); tmp+=tmp1; emit Errors(tmp); return -1; } // Close communication port nErr = AdsPortClose();// Close communication port if (nErr){ tmp= "Error: AdsPortClose: "; tmp1.setNum(nErr); tmp+=tmp1; emit Errors(tmp); return -1; } } //! Access an array in the PLC /*! An array, located in the PLC, is to be read by means of a read command. The variable is addressed here by its handle. The length of the whole array is provided as the length for the function AdsSyncReadReq(). The address of the first array element is given as variable. */ int Beckhoff::AccessAnArrayInThePLC() { long nErr, nPort; pAddr = &Addr; unsigned long lHdlVar; int nIndex; short Data[10]; char szVar []={"MAIN.PLCVar"}; // Open communication port on the ADS router nPort = AdsPortOpen(); nErr = AdsGetLocalAddress(pAddr); if (nErr){ tmp="Error: AdsGetLocalAddress: "; tmp1.setNum(nErr); tmp+=tmp1; emit Errors(tmp); return -1; } pAddr->port = AMSPORT_R0_PLC_RTS1; // Fetch handle for the PLC variable nErr = AdsSyncReadWriteReq(pAddr, ADSIGRP_SYM_HNDBYNAME, 0x0, sizeof(lHdlVar), &lHdlVar, sizeof(szVar), szVar); if (nErr){ tmp="Error: AdsSyncReadWriteReq: "; tmp1.setNum(nErr); tmp+=tmp1; emit Errors(tmp); return -1; } // Read values of the PLC variables (by handle) nErr = AdsSyncReadReq(pAddr, ADSIGRP_SYM_VALBYHND, lHdlVar, sizeof(Data), &Data[0]); if (nErr){ tmp="Error: AdsSyncReadReq: "; tmp1.setNum(nErr); tmp+=tmp1; emit Errors(tmp); return -1; } else { tmp=""; for (nIndex = 0; nIndex < 10; nIndex++){ tmp=+" Data["; tmp1.setNum(nIndex); tmp+=tmp1; tmp+="]: "; tmp1.setNum(Data[nIndex]); tmp+=tmp1; //emit SendData(tmp); } emit SendData(tmp); } // Close communication port nErr = AdsPortClose();// Close communication port if (nErr){ tmp= "Error: AdsPortClose: "; tmp1.setNum(nErr); tmp+=tmp1; emit Errors(tmp); return -1; } } //! 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 flag double word 0 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, ...). Advice: Don't use time intensive executions in callbacks. Remind to sync your callback and your mainthread, if you access each other (e.g. critical sections, mutex, events). */ int Beckhoff::EventDrivenReading() { // long nErr, nPort; //AmsAddr Addr; //PAmsAddr pAddr = &Addr; //ULONG hNotification, hUser; AdsNotificationAttrib adsNotificationAttrib; // Open communication port on the ADS router nPort = AdsPortOpen(); nErr = AdsGetLocalAddress(pAddr); if (nErr){ tmp= "Error: AdsGetLocalAddress: "; tmp1.setNum(nErr); tmp+=tmp1; emit Errors(tmp); return -1; } pAddr->port = AMSPORT_R0_PLC_RTS1; // Specify attributes of the notification adsNotificationAttrib.cbLength = 4; adsNotificationAttrib.nTransMode = ADSTRANS_SERVERONCHA; adsNotificationAttrib.nMaxDelay = 20000000; // 2sec adsNotificationAttrib.nCycleTime = 10000000; // 1sec // 32-bit variable (including pointers) that are passed to the callback function hUser = 3474573467; // Start transmission of the PLC variables nErr = AdsSyncAddDeviceNotificationReq(pAddr, 0x4020, 0, &adsNotificationAttrib, EventsInPlc, hUser, &hNotification); if (nErr){ tmp= "Error: AdsSyncAddDeviceNotificationReq: "; tmp1.setNum(nErr); tmp+=tmp1; tmp+="Notification: "; tmp1.setNum(hNotification); tmp+=tmp1; emit Errors(tmp); return -1; } // Wait for a key-press from the user //getch(); } int Beckhoff::StopEventDrivenReading() { // Finish transmission of the PLC variables nErr = AdsSyncDelDeviceNotificationReq(pAddr, hNotification); if (nErr){ tmp= "Error: AdsSyncDelDeviceNotificationReq: "; tmp1.setNum(nErr); tmp+=tmp1; emit Errors(tmp); return -1; } // Close communication port nErr = AdsPortClose();// Close communication port if (nErr){ tmp= "Error: AdsPortClose: "; tmp1.setNum(nErr); tmp+=tmp1; emit Errors(tmp); return -1; } } /* // 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"; // Output value of the variable cout << "Value: " << *(ULONG *)pNotification->data << '\n'; cout << "Notification: " << pNotification->hNotification << '\n'; // Convert time stamp to SYSTEMTIME LargeInteger.QuadPart = pNotification->nTimeStamp; FileTime.dwLowDateTime = (DWORD)LargeInteger.LowPart; FileTime.dwHighDateTime = (DWORD)LargeInteger.HighPart; FileTimeToSystemTime(&FileTime, &SystemTime); // Calculate time in local representation GetTimeZoneInformation(&TimeZoneInformation); SystemTimeToTzSpecificLocalTime(&TimeZoneInformation, &SystemTime, &LocalTime); // Output time stamp cout << LocalTime.wHour << ":" << LocalTime.wMinute << ":" << LocalTime.wSecond << '.' << LocalTime.wMilliseconds << " den: " << LocalTime.wDay << '.' << LocalTime.wMonth << '.' << LocalTime.wYear << '\n'; // Size of buffer in bytes cout << "SampleSize: " << pNotification->cbSampleSize << '\n'; // 32-bit variable (including pointers) that are set by AddNotification // (See main) cout << "hUser: " << hUser << '\n'; // Output 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(); } */ //!Access by variable name /*! The following program accesses a PLC variable that does not have an address. Access must therefore be made by the variable name. Once the PLC variable in the example program exceeds 10 it is reset to 0. All data that ADS devices make available to the outside is organised by means of IndexGroups and IndexOffset. An IndexGroup can be thought of as a table, with each entry being addressed by the IndexOffset. The TwinCAT PLC has, for example, IndexGroups in which the variables that belong to the input/output or flags regions are stored. IndexGroups are also available to the TwinCAT PLC through which system functions may be addressed. The IndexGroups ADSIGRP_SYM_HNDBYNAME and ADSIGRP_ SYM_VALBYHND are important for the example program. The IndexGroup ADSIGRP_SYM_HNDBYNAME is used to request a handle from a PLC variable identified by name. The variable can be accessed with the aid of this handle and the IndexGroup ADSIGRP_SYM_VALBYHND. The variable's handle is passed as the IndexOffset. */ void Beckhoff::AccessByVariableName() { int i=0; long nErr, nPort; AmsAddr Addr; PAmsAddr pAddr = &Addr; ULONG lHdlVar, nData; char szVar []={"MAIN.PLCVar"}; // Open communication port on the ADS router nPort = AdsPortOpen(); nErr = AdsGetLocalAddress(pAddr); if (nErr) qDebug() << "Error: AdsGetLocalAddress: " << nErr << '\n'; pAddr->port = AMSPORT_R0_PLC_RTS1; // Fetch handle for an <szVar> PLC variable nErr = AdsSyncReadWriteReq(pAddr, ADSIGRP_SYM_HNDBYNAME, 0x0, sizeof(lHdlVar), &lHdlVar, sizeof(szVar), szVar); if (nErr) qDebug() << "Error: AdsSyncReadWriteReq: " << tmp.setNum(nErr); do { // Read value of a PLC variable (by handle) nErr = AdsSyncReadReq( pAddr, ADSIGRP_SYM_VALBYHND, lHdlVar, sizeof(nData), &nData ); if (nErr){ qDebug() << "Fehler: AdsSyncReadReq: " << tmp.setNum(nErr); break; } else qDebug() << "Wert: " << tmp.setNum(nData); //cout.flush(); if (nData > 10) { // Reset the value of the PLC variable to 0 nData = 0; nErr = AdsSyncWriteReq(pAddr, ADSIGRP_SYM_VALBYHND, lHdlVar, sizeof(nData), &nData); if (nErr){ qDebug() << "Error: AdsSyncWriteReq: " << tmp.setNum(nErr); break; } } i++; }while(i<10); // read next value with RETURN, else end //Release handle of plc variable nErr = AdsSyncWriteReq(pAddr, ADSIGRP_SYM_RELEASEHND, 0, sizeof(lHdlVar), &lHdlVar); if (nErr) qDebug() << "Error: AdsSyncWriteReq: " << nErr << '\n'; // Close communication port nErr = AdsPortClose(); if (nErr) qDebug() << "Error: AdsPortClose: " << nErr << '\n'; } //!Read PLC variable declaration /*! The following information is transferred when accessing the variable declaration: Variable name Data type Length Address (IndexGroup / IndexOffset) Comment All the information listed above is transmitted in a data stream. Before this can be read, the first AdsSyncReadReq() is used to obtain the length. The data itself is transferred with the second AdsSyncReadReq(). The pchSymbols variable is a pointer, pointing to this region. The FOR-loop copies the corresponding data region into the pAdsSymbolEntry structure for each individual PLC variable. The individual information items in the PLC variables are stored in this structure. The macros PADSSYMBOLNAME, PADSSYMBOLTYPE and PADSSYMBOLCOMMENT simplify the evaluation of this data. */ void Beckhoff::ReadPlcVariableDeclaration() { long nErr, nPort; char *pchSymbols = NULL; UINT uiIndex; AmsAddr Addr; PAmsAddr pAddr = &Addr; AdsSymbolUploadInfo tAdsSymbolUploadInfo; PAdsSymbolEntry pAdsSymbolEntry; // Open communication port on the ADS router nPort = AdsPortOpen(); nErr = AdsGetLocalAddress(pAddr); if (nErr) qDebug() << "Error: AdsGetLocalAddress: " << nErr << '\n'; pAddr->port = AMSPORT_R0_PLC_RTS1; // Read the length of the variable declaration nErr = AdsSyncReadReq(pAddr, ADSIGRP_SYM_UPLOADINFO, 0x0, sizeof(tAdsSymbolUploadInfo), &tAdsSymbolUploadInfo); if (nErr) qDebug() << "Error: AdsSyncReadReq: " << nErr << '\n'; pchSymbols = new char[tAdsSymbolUploadInfo.nSymSize]; if(!pchSymbols){qDebug()<<"assertion rivi 547 beckhoff.cpp";} // Read information about the PLC variables nErr = AdsSyncReadReq(pAddr, ADSIGRP_SYM_UPLOAD, 0, tAdsSymbolUploadInfo.nSymSize, pchSymbols); if (nErr) qDebug() << "Error: AdsSyncReadReq: " << nErr << '\n'; // Output information about the PLC variables pAdsSymbolEntry = (PAdsSymbolEntry)pchSymbols; for (uiIndex = 0; uiIndex < tAdsSymbolUploadInfo.nSymbols; uiIndex++) { qDebug()<< PADSSYMBOLNAME(pAdsSymbolEntry) << "\t\t" << pAdsSymbolEntry->iGroup << '\t' << pAdsSymbolEntry->iOffs << '\t' << pAdsSymbolEntry->size << '\t' << PADSSYMBOLTYPE(pAdsSymbolEntry) << '\t' << PADSSYMBOLCOMMENT(pAdsSymbolEntry) << '\n'; pAdsSymbolEntry = PADSNEXTSYMBOLENTRY(pAdsSymbolEntry); //cout.flush(); } //getch(); // Close communication port nErr = AdsPortClose(); if (nErr) qDebug() << "Fehler: AdsPortClose: " << tmp.setNum(nErr); // Release memory if (pchSymbols) delete(pchSymbols); } //!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. uses void __stdcall ADS_StateCallback(AmsAddr*, AdsNotificationHeader*, ULONG); uses void __stdcall RouterCall(LONG); */ int Beckhoff::DetectStatusChangeTwinCatRouterAndPLC() { 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){ qDebug() << "Error: AdsGetLocalAddress: " << tmp.setNum(nErr);} pAddr->port = AMSPORT_R0_PLC_RTS1; nErr = AdsAmsRegisterRouterNotification(&RouterCall); if (nErr){ qDebug() << "Error: AdsAmsRegisterRouterNotification: " << tmp.setNum(nErr);} // 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, ADS_StateCallback, hUser, &hNotification); if (nErr) { qDebug() << "Error: AdsSyncAddDeviceNotificationReq: " << tmp.setNum(nErr);} // The following calls return errors if TwinCAT is halted nErr = AdsSyncDelDeviceNotificationReq(pAddr, hNotification); if (nErr) { qDebug() << "Error: AdsSyncDelDeviceNotificationReq: " << tmp.setNum(nErr);} nErr = AdsAmsUnRegisterRouterNotification(); if (nErr) { qDebug() << "Error: AdsAmsUnRegisterRouterNotification: " << tmp.setNum(nErr);} nErr = AdsPortClose(); if (nErr){ qDebug() << "Error: AdsPortClose: " << tmp.setNum(nErr);} return 1; }