# Eigener AMS/ADS Client



## Neals (2 Oktober 2008)

Hey Leute, da man beim Verwenden der angeboten ADS Dll's auf den installierten ADS Router angewiesen ist, versuche ich einen eigenen ADS Client zu schreiben. Nach der Beckhoff Doku soll das ja auch funktionieren. Wie in der ADS/AMS-Spezifikation angegeben soll das ganze als TCP-Telegramm versendet werden. Damit soll man z.B. auch unter Linux per ADS kommunizieren können, wo es ja nicht möglich ist den AMS Router zu installieren.

Nur habe ich das Problem, dass wenn ich mir den AMS Header ansehe, ich eine AMS Net ID und einen AMS Port benötige, die mein PC ja nicht hat, denn es ist ja kein AMS Router installiert.

Woher kriege ich eine AMSNetID und den AMS Port?


----------



## drfunfrock (2 Oktober 2008)

Such mal hier nach meinem Nick und linux. Ich glaube Zotos hat hier mal ein Posting inkl. Linux-Libs veröffentlicht.


----------



## Neals (13 Oktober 2008)

Dank Dr.FunFrock, jedoch war es nicht ganz das was ich gesucht habe.

Schreibe an einem eigenen AdsClient, der über Sockets und wahlweise TCP/UDP funktioniert. Das ganze unter C# und dem Compact Framework, was ja leicht auch auf das normale Framework umkompiliert werden kann.

Die Spezifikation die Beckhoff im InfoSys freigegeben hat, habe ich voll implementiert. Um jedoch Handles zu erstellen, an bestimmte Informationen vom Router, den Status des Systems und so zu gelangen, brauch ich mehr Informationen zum Protokoll.

Habe mir schon den Reflector genommen und den Code von der Beckhoff Dll angesehen, jedoch greift die immer auf Funktionen vom instalieren AdsMessageRouter zu.

Die normalen Funktionen wie Variablen aus der SPS holen und so funktionieren, VariablenInformationen auslesen und Handles erstellen klappt auch schon. Habe mir mühsam mit Wireshark die ganzen Telegramme auseinandergenommen und versucht nachzuvollziehen. Jedoch bin ich an einem Punk angekommen, an dem ich nicht weiter komme.

Weiß vlcht jemand ne freie Implementierung die man sich ansehen kann und Informationen zum Protokoll herrausholen kann oder kenn jemand weiter Spezifikationen die ich nutzen könnte?

Bin für jede Anregung dankbar!

PS: Der Weg ist das Ziel ;-)


----------



## drfunfrock (14 Oktober 2008)

Wo hast du denn ein Problem, denn das ADS-Protokoll ist doch dokumentiert? Wo ist die Doku denn lückenhaft? Ansonsten hat Beckhoff auf der Supplement-CD ein Beispiel, wie man an die Symbole herankommt. Dort kann man alle Variablen und die Info per ADS aus dem Server holen. 

Übrigens ein Problem war, dass ich immer hatte und weswegen ich mir eine Bibliothek baute, dass nach einem Verbindungsabbruch, die App neu gestartet werden musste, bzw. die Verbindung neu aufgebaut werden musste. Ich habe das mit einer Klassenbibliothek erledigt, die dafür einen extra Thread hat. Allerdings werden die Variablen gepollt und das geht nicht per Notification. Ein Umbau wurde mir zu heftig, weil ich dann 2 Bibliotheken benötigte. Eine für den einmaligen Zugriff auf eine Variable und die andere für den  Zugriff über Notifications.  Vielleicht kannste das ja einbauen und auch veröffentlichen?

Ich kann dir bei Bedarf auch den Code für den Thread zum Verbindungsaufbau schicken, weil der auf ein paar Eigenheiten von Twincat Rücksicht nimmt.


----------



## Neals (14 Oktober 2008)

Das währe nett, wenn du mir den schickst...

Wegen deinen Verbindungsabbrüchen, du meinst das die TCP Verbindung gekappt wird? Ansonsten ist Ads ja nicht Verbindungsorientiert, sondern eher so wie UDP aufgebaut. Man könnte ja auch einfach einen UDP Socket anlegen.

Probleme habe ich zum Beispiel beim verwenden der Dienste.
Ich möchte die Symbol Informationen auslesen. Dazu benutzte ich die IndexGroup SymbolInfoByName = 0xf007 und den ReadWrite Command. Da fängt es schon an, was soll ich versenden innerhalb der AdsDaten? Einfach nur einen String mit dem Namen der Variablen? Wenn ich den Response erhalte, wie sind die Daten darin angeordnet?
Beispielsweise IndexGroup 4 bytes, IndexOffset 4 bytes, dann Typ 2 byte etc.


----------



## drfunfrock (14 Oktober 2008)

Einen Verbindungsabbruch, kann man bekommen, wenn man ein Update der SPS macht oder einfach das Kabel fehlerhaft ist.

Hier die Routine: 

```
Private Sub ConnectStateMachine()
        While True
            Select Case Me.ADSConnectState
                Case ADS2.ADSConnectState.ADSInitialize
                    SendConnectMsg("Initialize " + Me.ADSAdress.ToString + ":" + Me.ADSPort.ToString)
                    Me.ADSConnectState = ADS2.ADSConnectState.ADSTryConnectToPLC
                    If Not RunThreads Then
                        Me.ADSConnectState = ADS2.ADSConnectState.ADSExit
                    End If

                Case ADS2.ADSConnectState.ADSTryConnectToPLC
                    SendConnectMsg("Connecting " + Me.ADSAdress.ToString + ":" + Me.ADSPort.ToString)
                    Try
                        Connect()
                        Me.ADSConnectState = ADS2.ADSConnectState.ADSWaitOnRun
                    Catch ex As TwinCAT.Ads.AdsException
                        Me.ADSConnectState = ADS2.ADSConnectState.ADSTryConnectToPLC
                    End Try
                    If (Not RunThreads) Then
                        Me.ADSConnectState = ADS2.ADSConnectState.ADSExit
                    End If

                Case ADS2.ADSConnectState.ADSWaitOnRun
                    SendConnectMsg("Check for PLC-state RUN at " + Me.ADSAdress.ToString + ":" + Me.ADSPort.ToString)
                    Try
                        If Me.ADSClient.ReadState().AdsState = TwinCAT.Ads.AdsState.Run Then
                            Me.ADSConnectState = ADS2.ADSConnectState.ADSCheckPLCProgram
                        End If
                    Catch ex As TwinCAT.Ads.AdsException
                        Disconnect()
                        Me.ADSConnectState = ADS2.ADSConnectState.ADSTryConnectToPLC
                    End Try
                    If (Not RunThreads) Then
                        Me.ADSConnectState = ADS2.ADSConnectState.ADSExit
                    End If

                Case ADS2.ADSConnectState.ADSCheckPLCProgram
                    SendConnectMsg("Check for PLC-program at " + Me.ADSAdress.ToString + ":" + Me.ADSPort.ToString)
                    Try
                        Dim plc_version As New PLCVarString(Me, ".VERSION", 1)
                        Me.ADSConnectState = ADS2.ADSConnectState.ADSConnectFields
                        plc_version.Dispose()
                    Catch ex As TwinCAT.Ads.AdsException
                        Me.ADSConnectState = ADS2.ADSConnectState.ADSCheckPLCProgram
                    End Try
                    If (Not RunThreads) Then
                        Me.ADSConnectState = ADS2.ADSConnectState.ADSExit
                    End If

                Case ADS2.ADSConnectState.ADSConnectFields
                    SendConnectMsg("Connecting PLC vars at " + Me.ADSAdress.ToString + ":" + Me.ADSPort.ToString)
                    Try
                        Me.GetPLCVars()
                        Dim plc_version As New PLCVarString(Me, ".VERSION", 50)
                        Me.ADSConnectState = ADS2.ADSConnectState.ADSConnectFields
                        plc_version.Dispose()
                        Me.ADSConnectState = ADS2.ADSConnectState.ADSConnected

                    Catch ex As TwinCAT.Ads.AdsException
                        Me.DropPLCVars()
                        Me.ADSConnectState = ADS2.ADSConnectState.ADSCheckPLCProgram
                    End Try
                    If (Not RunThreads) Then
                        Me.ADSConnectState = ADS2.ADSConnectState.ADSExit
                    End If

                Case ADS2.ADSConnectState.ADSConnected
                    SendConnectMsg("Connected at " + Me.ADSAdress.ToString + ":" + Me.ADSPort.ToString)
                    SyncLock Me.lock
                        If Me.ADSConnectState = ADS2.ADSConnectState.ADSConnected Then
                            Try
                                If Me.ADSClient.ReadState().AdsState <> TwinCAT.Ads.AdsState.Run Then
                                    Me.ADSConnectState = ADS2.ADSConnectState.ADSWaitOnRun
                                    Me.DropPLCVars()
                                End If
                            Catch ex As TwinCAT.Ads.AdsException
                                Me.ADSConnectState = ADS2.ADSConnectState.ADSCleanUp
                            End Try
                        End If
                        If (Not RunThreads) Then
                            Me.ADSConnectState = ADS2.ADSConnectState.ADSExit
                        End If
                    End SyncLock

                Case ADS2.ADSConnectState.ADSCleanUp
                    SendConnectMsg("Clean up " + Me.ADSAdress.ToString + ":" + Me.ADSPort.ToString)
                    Me.ADSCleanUp()
                    Me.ADSConnectState = ADS2.ADSConnectState.ADSTryConnectToPLC

                Case ADS2.ADSConnectState.ADSExit
                    SendConnectMsg("Closed " + Me.ADSAdress.ToString + ":" + Me.ADSPort.ToString)
                    Me.ADSCleanUp()
                    Exit While
            End Select
            Thread.Sleep(timePLC)
        End While
    End Sub
```

Wie gesagt, schau einfach mal auf der Supplement-CD nach. Da war ein .Net-Beispiel!


----------



## Neals (14 Oktober 2008)

Danke dir, werde mal die CD durchwühlen, im InfoSystem findet man auch noch interessante Sachen, ADS bietet ja echt viele funktionen. In der Spezifikation sind ja nur die normalen Sachen dokumentiert.

Für Änderungen der Handles beim Update (Online-Change) habe ich auch ne Lösung gefunden:
http://infosys.beckhoff.com/index.p...csample_vc/html/tcadsdll_api_cpp_sample12.htm


----------



## drfunfrock (14 Oktober 2008)

Berichte mal, wenn du weitergekommen bist.


----------



## Neals (16 Oktober 2008)

Leider die letzten Tage wenig Zeit gehabt um weiter dran zu arbeiten, was mir aber sehr geholfen hat ist die Device-Dokumentation für die SPS.


----------



## MarkusP (16 Oktober 2008)

Neals schrieb:


> Ich möchte die Symbol Informationen auslesen. Dazu benutzte ich die IndexGroup SymbolInfoByName = 0xf007 und den ReadWrite Command.



Erfahrungsgemäß kann dies bei sehr vielen Variablen zum Teil etwas lange dauern. Dafür hast Da aber immer die aktuellen Informationen direkt vom System. Alternativ könntest Du auch das TPY File verwenden, dort steht eigentlich alles drinnen. Allerdings musst Du Dich dann um ev. geänderte Variablen Handles bei Änderungen kümmern. Solange sich zumindest der Variablenname nicht ändert, klappt das. Wir sind gerade daran, einen OPC Server für Beckhoff zu basteln. (ADS)

Warum willst Du eigentlich auf den installierten ADS Router verzichten? So empfiehlt z.B. Beckhoff TwinCAT CP zu installieren, da dann die beste Funktionalität gewährleistet ist, und Du hast keinen Kopfweh.

Viel Spaß noch!


----------



## Neals (17 Oktober 2008)

MarkusP schrieb:


> Viel Spaß noch!


Darum geht es mir in erster Linie  ausserdem lerne ich dabei noch was und vielleicht kommt am Ende ja sogar was ganz gutes dabei rum.

Beispiele:
Wenn ich einen Server habe, möchte ich da ungerne eine Echtzeitinstanz drauf installieren. Meine Software ist unabhängig von jeglicher Beckhoff-Installation. Ausserdem hat ADS ziemliche Schwierigkeiten mit Routing, was durch die Kapselung in TCP erledigt ist. Ich kann meinen Client erweitern und zusätzliche Funktionen einbauen, bin nicht mehr eingeschränkt durch die Beckhoff-Dll. Baue meine dll modular auf, das man auch ein Server implementieren könnte. Da bei Beckhoff alles auf ADS aufbaut, habe man ja extrem viele Möglichkeiten damit zu arbeiten. Die ADS Bauteile sind alle inklusive und kostenlos. Kann mir sehr leicht mit Hilfe der Datei nen Proxy zwischen z.B. ADS und ner Datenbank bauen. Dann könnte ich aus der SPS über ADS auf meine Datenbank zugreifen, lesen, schreiben. Mir fällt da viel ein was ich damit machen könnte. 

Warum baut ihr denn den OPC Server, den gibts doch schon: TwinCAT OPC Server.


----------



## MarkusP (17 Oktober 2008)

Find' ich schon gut, dass es immer noch Idealisten wie Dich gibt, die auch noch des Spaßes wegen so was auf die Beine stellen! :s12:

Den OPC-Server machen wird deshalb, da ich beim Beckhoff OPC einiges vermisse, das ich von früher verwendeten Servern kenne, aber nicht missen möchte. (Inbetriebnahmetools, Debugging, Fehlerprotokollierung etc.) Und laut Google, gibt es für Beckhoff (via ADS wohlgemerkt) keinen anderen OPC-Server! Also müsste da doch "internationaler" Bedarf bestehen....

An Deiner Lösung hätte ich auch Interesse, vielleicht können wir uns ja austauschen?

Schönen Tag noch


----------



## Neals (29 Oktober 2008)

Habe jetzt was vorläufiges fertig.
Aber ganz nett: Habe ne Methode geschrieben, mir der sich Routen auf Geräten eintragen lassen, ist ganz Hilfreich, wenn man kein TwinCAT hat :TOOL:
Wer sich das mal ansehen will, schickt einfach seine Mailadresse per PM an mich und ich schick ihm das Programm.

Habe noch Probleme bei Notifications:
Ich habe ja jetzt alles Synchron gemacht, zB:
Schicke Packet Read, warte auf Eingang von Daten, auswerten und zurückgeben.

Die Notifications kommen jetzt ja zwischendurch, entweder schreibe ich den kompletten Client Multithreaded, dann müsste man mit jeder Funktion nen Callback mitgeben, ein Thread der durchgehend eingehende Daten ließt und danach dann den richtigen Callback feuert. Das währe eh der nächste Schritt gewesen, wenn alles synchron läuft, jedoch sollten die synchronen Methoden eigendlich bestehen bleiben.

Mir fällt keine Art ein, wie ich in den synchronen Client die Notifications einbauen soll.


----------



## drfunfrock (29 Oktober 2008)

Richtig, du musst den synchronen Teil, vom asynchronen Teil trennen. Ist leider nicht anders zu machen. Irgendwie überschneiden sich dabei die Klassen. 


```
Variable ---> Int ----> Access Async 
                       ----> Access Sync
Variable ---> Byte ----> Access Async 
                        ----> Access Sync
```
Massiver Threadeinsatz ist eigentlich nur bei der Kopplung Programm-Twincat gefragt. Mit async-Logik braucht es eigentlich keine weiteren Threads. Das hat auch später im Anwenderprogramm Vorteile, weil man da dann nicht bei den Controls darauf Rücksicht nehmen muss.


----------



## Neals (29 Oktober 2008)

Jetzt ist auch eine Implementierung für UDP eingebaut, damit ist man nicht mehr auf TCP beschränkt... Nachteil an der Sache ist, das ich den Port von TwinCAT verwenden muss. Um an die eingehenden Daten zu kommen, muss also TwinCAT aus sein... deswegen überlege ich die UDP Lösung raus zu nehmen.

Sorry Frog, aber irgendwie hab ich nicht ganz verstanden wie du das meinst...

Ich muss ja einen Thread haben, der durchgehend Empfängt und guckt ob ne Notification da ist. Hatte überlegt, bei ner Anfrage den zu blockieren und Synchron weiter zu arbeiten. Dann sende, Daten empfangen, wenns ne Notification ist, Event feuern und nochmal empfangen... wenn Daten da sind, verarbeiten, ausgeben, Thread wieder starte.


----------



## drfunfrock (30 Oktober 2008)

Eine Notification arbeitet doch so, dass du eine Msg. von der SPS bekommst. Eigentlich braucht es nur einen Thread, der die Variablen aktualisiert. 

Ansonsten wärst du gezwungen, für jede Notification einen Thread aufzumachen. Das dumme dabei ist, dass dann auch bei der Programmierung der GUI nicht einfach losprogammiert werden kann, sondern da bestimmte Regeln eingehalten werden müssen. Bisher habe ich mich darum drücken können, aber wenn man auf VS2008 schaut, wird das bestimmt nicht mehr möglich sein.


----------



## LowLevelMahn (30 Oktober 2008)

*ich würdes es möglicherweise so machen*

ich würde erstmal folgende einschränkungen machen:

pro thread nur eine synchronaktion - d.h. dein read, write oder notify ist blockierend

jeder thread braucht eine "connection" zu deinem receiver_thread

connection
  buffer: answer_data
  event: answer_received

mit irgendwas in deinen empfangsdaten musst du die connection(client)
eindeutig identifizieren und zuordnen - damit du den answer_received.event der entsprechenden connection triggern kannst

also in der art

communicator::
receiver_thread
{
    buffer: data;
    while ( true )
    {
       dein_ADS_receive( data );

       // informieren die entsprechende connection
       map[ data.key ].anwer_data = data;
       map[ data.key ].answer_received.set(); // feedback an den client
    }
}

dann kannst du schön waitforsingleobject - or whatever auf antworten für deine "connection" warten - das reduziert die menge der freifliegenden callbacks

connection = communicator::connect();

read_var test_read( connection, "welche var" );

test_read.request();
  --> schickt die anfrage über die leitung
  --> (merkt sich im sender_thread das nachricht erwartet wird)

test_read.wait( timeout );
  --> wartet darauf das connection.answer_received 
durch den reciver_thread signalisiert wird

x = test_read.value();

mit einer notifiy koennte es so aussehen

notifiy test_notfy( connection, "auf was auch immer" );

test_notify.start();

while( test_notify.wait() )
{
    x = test_notiy.value();

    test_notify.stop(); // nur einmal erwarten
}

communicator::disconnect( connection );

und die Anbindung an ein GUI(Konsolen) System würde ich dann darauf setzen weil das gibts viele Wege - Windows Messages, COM, QT-Slots usw.

desweiteren hast du dann in der basis eine voll mach-dein-threading-selber system das zum benutzer hin leicht auf synchrone konstruktionen ala

read_synchron( connection, var )
{
   read_var var( connect, var ) 
   var.wait();
}

verbogen werden kann

hoffe mein c++-java-pascal-artiger pseudocode ist nicht zu verwirrend


----------



## drfunfrock (30 Oktober 2008)

Warum sollte man mehrere Threads aufmachen, wenn einer reicht? Sobald etwas über den die Verbindung hineinkommt und es gibt nur eine(!), müssen die entsprechenden Variablen ein Update erfahren. Hätte es pro Variable eine Verbindung gegeben, wäre ein Thread pro Variable sinnvoll gewesen.


----------



## LowLevelMahn (30 Oktober 2008)

*ich weiss schon was du meinst*

Ich hab ja auch nicht über den Teil gesprochen den der Benutzer in
die Finger bekommt - eher den Aufbau der dahinterliegenden Kommunikationsschicht - um seine (a)synchron Aktione besser(leichter) implementieren zu können ohne eine Callback-Party zu starten

noch dazu ist er dann freier in der Anbindung andere System z.b. VB würde sicher von einem COM-Frontend profitieren, QT denke eher an einer SLOT integration - und in der Konsole gibts das alles nicht - da hätte ich eher gern so einen Wait-Mechanismus

und das schöne daran ist - deine Anforderung oder Idee lässt sich damit genauso implementieren

ciao LowLevelMahn

BTW: 

die connection ist keine ADS-Verbindung sondern eher ein Identifikationshandle für die client(read,write,notify) <-> receiver_thread Kommunikation
wobei Client auch wieder ein grosses Wort für ein Trivialding ist

und noch was: bist du dir bewusst das über den receive viele verschiedene pakete kommen, d.h. unsortiert read- und write-request antworten durchmischt mit notifies?
Neals Problem ist das er gerne ein Verhalten in der Leitung hätte als würde alles synchron ablaufen (vereinfach die Implemtierung sehr sehr stark) - aber trotzedem nicht die
asynchronen sachen wie die notifies (die einfach so zwischendurch das plappern anfang) mit wilden orgien da reinzupfuschen

mein Ansatz verändert mal primär das Verhalten so das sich die einzelnen Funktionen nur mit ihren Aufgaben beschäftigen müssen - von was du spricht ist schon ein Treppenstufe weiter oben

@Neals
wie kannst du die Pakete eindeutig Identifierzen ( also z.B. das Paket gehört zu Read1, das zu Write2 usw.)? 
und unter welchem System entwickelst du gerade? Windows, WinAPI, C/C++


----------



## drfunfrock (30 Oktober 2008)

Eine Callback-Party braucht es auch nicht, wenn die Bibliothek die Werte der Variablen updatet. Ich mache es jedenfalls so mit meiner Lib.

Die Kunst besteht eher darin, die Verbindung nach einem Abbruch (wegen Kabel etc) abzubauen und wieder aufzubauen, damit der PC nicht irgendwann stehenbleibt. Du brauchst eine Liste oder ähnliches, in der die Daten zu allen Variablen gespeichert werden. Der Kommunikationsthread sorgt dann für den Abbau und den Neuaufbau. 

Und COM benötigt man eigentlich kaum, denn .Net bietet soweit alles. Nur 1 oder 2 Interfaces müssen definiert werden.


----------



## LowLevelMahn (30 Oktober 2008)

*deswegen denke ich das wir aneinander vorbeireden*

wie schaffst du es das deine read/write_var funktionen und deinen 
notifiy entgegennahme sauber gretrennt sind?
dates du einfach die variablen up wenn anstatt deine read-anwort ein notify reinflattert? - ich denke das will er nicht so haben (find ich auch ein bischen schmutzig)

zu COM und .Net - meine Idee (so mach ichs in meiner Lib) lässt sich auf mehrere Welten adaptieren - also kein "es funktioniert gut weil ich .Net bei mir habe" - sonst würde Neals wohl nicht von Linux sprechen (und ich wette das er nicht Mono im Kopf hat)

und ich hab ja schon gesagt das es nicht der Teil ist den der Benutzer sieht - also steckt das alles doch in der Bibliothek - so wie bei dir
(nur das deine Features Teile der Realisierung sind) und mein Thread-Count ist auch nicht wirklich groesser als bei dir - ein Tribut an die saubere Lösung

mfg LowLevelMahn


----------



## drfunfrock (30 Oktober 2008)

Asynchroner und synchroner Teil müssen getrennt werden. Die Notifys sind ja in erster Linie nur dazu da Variablen zu lesen. 

Das mit Linux hatte ich schon wieder glatt vergessen. Da haste Recht. 

Zum Thema Verbindung. Selbst wenn die ADL-Lib nur ein Handle bereitstellt, es ist eine Netzwerkverbindung zu einer Adresseort und wirklich nur eine. Daher brauch es auch nur einen Thread für alle Variablen evtl. optional mit Callback.


----------



## LowLevelMahn (30 Oktober 2008)

*jetzt sind wir wieder auf einer ebene*



> Zum Thema Verbindung. Selbst wenn die ADL-Lib nur ein Handle bereitstellt, es ist eine Netzwerkverbindung zu einer Adresseort und wirklich nur eine. Daher brauch es auch nur einen Thread für alle Variablen evtl. optional mit Callback.



ist 100% mir klar - mein Ansatz verhindert nur das man mit einem Callback kontextbeschmutzend durchs System wandert - ich brauch keinen - ich hab nur einen auf signalisierung wartenden Abnehmer der Information


----------



## drfunfrock (30 Oktober 2008)

Ich glaube, ich bin zur Zeit viel zu sehr im Denken in .Net gefangen. Abseits davon sehe ich entweder nur Callbacks oder eine Event-Queque, um daraus wieder Aufrufe von Methoden von Objekten zu machen. 

Vielleicht kannst du mir deinen Ansatz etwas anders erklären?


----------



## Neals (30 Oktober 2008)

Hab jetzt nen Mutex, zum stoppen verwendet.
Starte EINEN NotificationThread, der durchgehen (in einer Schleife) nachsieht ob Daten eingehen und bei einer Notifcation das Event feuert.
Wenn jetzt eine Anfrage gestellt wird (bsp. Read), werden die Daten gesendet und der Mutex gesetzt. Dadurch wird das abarbeiten des NotificationThreads gestoppt. Jetzt wird synchron empfangen und differenziert. Wenn es eine Notification ist, wird das Event gefeuert und die Schleife neu gestartet. Wenn es die Antwort auf meine Anfrage ist, werden die Daten zurückgegeben, das Mutex wieder resettet und der NotificationThread läuft somit weiter.

Danke euch beiden für die heiße Diskussion *g*

Benutze die InvokeId des Protokolls zum identifizieren der Packete, programmiere in C# und dem Compact Framework. Das mit Linux am Anfang war nur nen Beispiel zur Verwendung.


----------



## drfunfrock (30 Oktober 2008)

Kann man die Packete nicht so lesen, dass der Thread blockiert wird, anstatt dass man pollt? Ich dachte immer, dass wäre mit IP am elegantesten?


----------



## Neals (4 November 2008)

So, jetzt läufts alles voll synchron und ohne Threads... habs mit dem Windows.Form.Timer umgesetzt



> class ReceiveTimer
> {
> private readonly EventHandler receiveCallback;
> private readonly Timer timer;
> ...


Habs jetzt alles hin, Grundlagen sind fertig, Notifications werden empfangen... bin gerade dabei eventuelle Fehler abzufangen, die Events einzubinden und Doku zu schreiben.

Habe schon bissl am asynchronen Client geschrieben... nur bin ich mir über den Entwurf nicht sicher. Empfangen und senden usw. läuft alles super, habe nur Probleme mit den Funktionsaufrufen. Es müsste ja jeder Funktion des Clients nen Callback übergeben werden. Um dann auch die entsprechenden Rückgabewerte übergeben zu können, müsste für jede Funktion nen extra Callback erstellt werden, das ist doch ein wenig lästig für den User?! Jemand ne Idea, wie ich die Anzahl an Callback-Delegates verringern kann?

Welche Features fehlen noch allgemein? Welche sollten implementiert werden? Auf was sollte ich Rücksicht nehmen?


----------



## holgermaik (14 Januar 2016)

Hallo Neals
Stehe gerade vor dem gleichen Problem da Twincat CP nicht mehr als Download angeboten wird. (oder ich habs nicht gefunden)
Hast du deinen Client lauffähig zu Ende gebracht und würdest ihn teilen?
Holger


----------



## Guga (15 Januar 2016)

Hallo Holgermaid,

TwinCAT CP kannst du installieren über das TwinCAT2 Setup.
Alernativ (was ich bevorzugen würde) wäre das TwinCAT3 ADS-Setup. Hier wird "nur" der Router ...  installiert ohne Echtzeitkomponente o.ä.

Guga


----------



## holgermaik (15 Januar 2016)

Hallo Guga


> TwinCAT CP kannst du installieren über das TwinCAT2 Setup.


Das will ich ja genau nicht. Eigentlich will ich gar kein Twincat.


> ..TwinCAT3 ADS-Setup. Hier wird "nur" der Router ...  installiert


Das schau ich mir mal an. Als Minimalvariante
Grüße Holger


----------

