Beispiel03: Der in C++ geschriebene TC3 ADS Server

In diesem Artikel wird die Erstellung eines als ADS Server agierenden TC3 C++ Moduls beschrieben.
Der Server stellt eine ADS-Schnittstelle zum Starten / Stoppen / Zurücksetzen einer Zählervariablen im C++ Modul bereit.

Download

Hier erhalten Sie den Quellcode für dieses Beispiel.

1. Entpacken Sie die heruntergeladene ZIP-Datei.
2. Öffnen Sie mittels eines Visual Studios, in dem TwinCAT installiert ist, das Projekt über Open Project ….
3. Konfigurieren Sie das Signieren für dieses Projekt, indem Sie auf der Seite unter Rechtsklick auf dem Projekt->Properties->Tc Sign die TwinCAT Signierung anschalten und Ihr Zertifikat und ggf. Passwort konfigurieren.
Weitere Informationen zur Signierung der C++ Projekte erhalten Sie hier.
4. Wählen Sie Ihr Zielsystem aus.
5. Bauen Sie das Beispiel (z. B. Build->Build Solution).
6. Aktivieren Sie die Konfiguration mit einem Klick auf Beispiel03: Der in C++ geschriebene TC3 ADS Server 1:.
Das Beispiel ist einsatzbereit.

Beschreibung

Dieses Beispiel beinhaltet ein C++ Modul, das als ADS Server agiert, der einen Zugang zu einem Zähler gewährt, der gestartet, gestoppt und gelesen werden kann.

Die Header-Datei des Moduls definiert die Zählervariable m_bCount, und die entsprechende .cpp-Datei initialisiert den Wert im Konstruktor und implementiert die Logik in der CycleUpdate Methode.

Die Methode AdsReadWriteInd in der .cpp-Datei analysiert die eingehenden Meldungen und sendet die Rückgabewerte zurück. Für einen weiteren hinzugefügten Meldungstyp wird ein define in der Header-Datei hinzugefügt.

Details, wie die Definition der ADS-Meldungstypen, werden im folgenden Kochbuch beschrieben, wo Sie das Beispiel manuell zusammenstellen können.

Kochbuch

Nachfolgend werden die einzelnen Schritte der Erstellung des C++ Moduls beschrieben.

1. Erstellen Sie eine neue TwinCAT 3 Project Solution

Folgen Sie den Schritten für die Erstellung eines neuen TwinCAT 3 Projekts.

2. Erstellen Sie ein C++ Projekt mit ADS Port

Folgen Sie den Schritten für die Erstellung eines neuen TwinCAT 3 C++ Projekts.

Wählen Sie im Class templates-Dialog TwinCAT Module Class with ADS port.

3. Fügen Sie dem Projekt die Beispiellogik hinzu

1. Öffnen Sie die Header-Datei <MyClass>.h (in diesem Beispiel Module1.h) und fügen den Zähler m_bCount als neue Membervariable in den geschützten Bereich hinzu:
class CModule1
    : public ITComObject
    , public ITcCyclic
    ,...
{
public:
    DECLARE_IUNKNOWN()
    ....
protected:
    DECLARE_ITCOMOBJECT_SETSTATE();
///<AutoGeneratedContent id="Members">
    ITcCyclicCallerInfoPtr m_spCyclicCaller;
    .....
///</AutoGeneratedContent>
    ULONG m_ReadByOidAndPid;
    BOOL m_bCount;
};
2. Öffnen Sie die Klassendatei <MyClass>.cpp (in diesem Beispiel Module1.cpp) und initialisieren die neuen Werte im Konstruktor:
CModule1::CModule1()
    .....
{
    memset(&m_Counter, 0, sizeof(m_Counter));
    memset(&m_Inputs, 0, sizeof(m_Inputs));
    memset(&m_Outputs, 0, sizeof(m_Outputs));
    m_bCount = FALSE; // by default the counter should not increment
    m_Counter = 0;    // we also initialize this existing counter
}
Der Beispielcode ist hinzugefügt.

3.a. Fügen Sie der ADS-Serverschnittstelle die Beispiellogik hinzu.

Normalerweise empfängt der ADS Server eine ADS-Meldung, die zwei Parameter (indexGroup und indexOffset) und gegebenenfalls weitere Daten pData enthält.

ADS-Schnittstelle entwerfen
Unser Zähler sollte gestartet, gestoppt, zurückgesetzt, mit Wert überschrieben werden oder dem ADS Client auf Anfrage einen Wert liefern:

indexGroup

indexOffset

Beschreibung

0x01

0x01

m_bCount = TRUE, Zähler wird inkrementiert.

0x01

0x02

Zählerwert wird ADS Client übergeben.

0x02

0x01

m_bCount = FALSE, Zähler wird nicht mehr inkrementiert.

0x02

0x02

Zähler zurücksetzen.

0x03

0x01

Zähler mit vom ADS Client übergebenen Wert überschreiben.

Diese Parameter sind in modules1Ads.h definiert – ändern Sie den Quellcode, um einen neuen Befehl für IG_RESET hinzuzufügen.

#include "TcDef.h"
enum Module1IndexGroups : ULONG
{
    Module1IndexGroup1 = 0x00000001,
    Module1IndexGroup2 = 0x00000002, // add command
    IG_OVERWRITE = 0x00000003 // and new command
};

enum Module1IndexOffsets : ULONG
{
    Module1IndexOffset1 = 0x00000001,
    Module1IndexOffset2 = 0x00000002
};

Ändern Sie den Quellcode in Ihrer <MyClass>::AdsReadWriteInd() Methode (in diesem Falle in Module1.cpp).

switch(indexGroup)
{
case Module1IndexGroup1:
    switch(indexOffset)
    {
    case Module1IndexOffset1:
        ...
        // TODO: add custom code here
        m_bCount = TRUE; // receivedIG=1 IO=1, start counter
        AdsReadWriteRes(rAddr, invokeId, ADSERR_NOERR, 0,NULL);
        break;
    case Module1IndexOffset2:
        ...
        // TODO: add custom code here
        // map counter to data pointer
        pData = &m_Counter;     // received IG=1 IO=2, provide counter value via ADS
     AdsReadWriteRes(rAddr, invokeId, ADSERR_NOERR, 4 ,pData);
//comment this: AdsReadWriteRes(rAddr, invokeId,ADSERR_NOERR, 0, NULL);
     break;
    }
    break;
case Module1IndexGroup2:
    switch(indexOffset)
    {
    case Module1IndexOffset1:
     ...
     // TODO: add custom code here
    // Stop incrementing counter
    m_bCount = FALSE;
     // map counter to data pointer
    pData = &m_Counter;
     AdsReadWriteRes(rAddr, invokeId, ADSERR_NOERR, 4,pData);
     break;
case Module1IndexOffset2:
    ...
    // TODO: add custom code here
    // Reset counter
    m_Counter = 0;
    // map counter to data pointer
    pData = &m_Counter;
     AdsReadWriteRes(rAddr, invokeId, ADSERR_NOERR, 4, pData);
     break;
}
break;
case IG_OVERWRITE:
    switch(indexOffset)
    {
    case Module1IndexOffset1:
    ...
     // TODO: add custom code here     // override counter with value provided by ADS-client
     unsigned long *pCounter = (unsigned long*) pData;
     m_Counter = *pCounter;
     AdsReadWriteRes(rAddr, invokeId, ADSERR_NOERR, 4, pData);
     break;
}
break;
}
break;
default:
    __super::AdsReadWriteInd(rAddr, invokeId, indexGroup,indexOffset, cbReadLength, cbWriteLength, pData;
     break;
}

3.b. Fügen Sie die Beispiellogik in den zyklischen Teil ein

Die Methode <MyClass>::CycleUpdate() wird zyklisch aufgerufen - das ist die Stelle, wo die Logik zu verändern ist.

// TODO: Replace the sample with your cyclic code
m_Counter+=m_Inputs.Value; // replace this line
m_Outputs.Value=m_Counter;

In diesem Falle wird der Zähler mCounter inkrementiert, wenn die boolsche Variable m_bCount TRUE ist.

Fügen Sie diesen If-Fall in Ihre zyklische Methode ein.

HRESULT CModule1::CycleUpdate(ITcTask* ipTask,
ITcUnknown* ipCaller, ULONG context)
{
HRESULT hr = S_OK;
// handle pending ADS indications and confirmations
CheckOrders();
....
// TODO: Replace the sample with your cyclic code
if (m_bCount)    // new part
{
    m_Counter++;
}
m_Outputs.Value=m_Counter;
}

4. Server-Beispiel ausführen

1. Führen Sie den TwinCAT TMC Code Generator aus, um die Ein-/Ausgänge für das Modul bereitzustellen.
2. Speichern Sie das Projekt.
3. Kompilieren Sie das Projekt.
4. Erstellen Sie eine Modulinstanz.
5. Erstellen Sie eine zyklische Task und konfigurieren Sie das C++ Modul für die Ausführung in diesem Kontext.
6. Scannen Sie die Hardware IO und ordnen Sie das Symbol Value von Ausgängen bestimmten Ausgangsklemmen zu (dies ist optional).
7. Aktivieren Sie das TwinCAT Projekt.
Das Beispiel ist einsatzbereit.

5. Finden Sie den ADS Port der Modulinstanz heraus

Im Allgemeinen kann der ADS Port

In diesem Beispiel ist die Standardeinstellung (flexibel halten) gewählt. Zunächst ist der ADS Port zu ermitteln, der dem Modul, das soeben aktiviert wurde, zugewiesen wurde:

1. Navigieren Sie zur Modulinstanz.
2. Wählen Sie den Karteireiter Parameter Online.
Dem ADSPort ist 0x8235 bzw. dezimal 33333 zugewiesen (das kann in Ihrem Beispiel anders sein). Werden mehr und mehr Instanzen erstellt, erhält jede Instanz ihren eigenen eindeutigen AdsPort.
Der Zähler steht immer noch auf „0“, da die ADS-Meldung zum Starten der Inkrementierung nicht gesendet worden ist.
Beispiel03: Der in C++ geschriebene TC3 ADS Server 2:
Der Server-Teil ist abgeschlossen - fahren Sie fort mit ADS Client sendet die ADS-Meldungen.