Ads funktioiden avulla voi toteuttaa kättetelyn kättelyn c++ ohjelman ja Beckhoffin logikan logiikan välillä.
Yksinkertainen esimerkki
Code Block |
---|
title | Window määrittelyjä |
---|
collapse | true |
---|
|
#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 |
...
...
Esimerkkejä
ADS-DLL Sample01.zip
ADS-DLL Sample02.zip
ADS-DLL Sample03.zip
ADS-DLL Sample04.zip
BechoffEsim.zip
projektitiedostoon kirjaston polku | collapse | true |
---|
|
LIBS += "c://twincat//AdsApi//tcadsdll//lib//TcAdsDll.lib" |
Code Block |
---|
title | otsikkotiedosto |
---|
collapse | true |
---|
|
#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 |
---|
title | luokan funktiot |
---|
collapse | true |
---|
|
#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;
}