# AGLink und VB.Net --> Umsteiger von Softing OPC



## Sönke Schlüter (22 November 2019)

Guten Abend,

dies ist mein erster Beitrag. 
Nach einiger Zeit steige ich nun wieder ins Programmieren ein. Früher konnte ich relativ einfach mit Softing OPC die Kommunikation zu meinen SPS ermöglichen.

Jetzt bin ich aktuell dabei mich in AGLink einzuarbeiten und habe mir ein erstes kleines Beispiel mit Hilfe der Anleitungen geschrieben.

Allerdings erhalte ich immer in dieser Zeile result = opc.agl.Symbolic_ReadMixEx(readwritestructures)
folgende Fehlermeldung:
22.11.2019 17:18:11 Fehler in Sub: Polling in Zeile: 283
Message:
Der Objektverweis wurde nicht auf eine Objektinstanz festgelegt.
Stacktrace:
   bei Accon.AGLink.Converter.ToGcHandle(SymbolicRW[] buffer)
   bei Accon.AGLink.AGL4.Symbolic_ReadMixEx(Int32 connNr, SymbolicRW[] symbolicRW, Int32& sError, Int32 timeout)
   bei Accon.AGLink.AGLink4Tia.Symbolic_ReadMixEx(SymbolicRW[] symbolicRw, Int32& sError, Int32 timeout)
   bei Accon.AGLink.AGLink4Tia.Symbolic_ReadMixEx(SymbolicRW[] symbolicRw)
   bei XXXXXX\frm_haupt.vb:Zeile 283.
Es klappt alles bis zu der entsprechenden Zeile. SPS-Nummer wird ausgelesen. TIA-Symbole werden vom PLC gelesen etc.


Der aus meinen Augen relevante Code-Teil sieht wie folgt aus:


> Try
> opc = New progparas With {
> .verbose = True,
> .agl = AGL4ConnectionFactory.CreateTiaInstance(0, 0, 1)
> ...




Wäre super, wenn ein Erfahrener mir helfen könnte 

Vielen Dank und viele Grüße,

Sönke


----------



## Rainer Hönle (25 November 2019)

Hallo Sönke,

mir fällt hier nur folgendes auf:


```
Dim buffer(buffersize - 1) As Byte
                MsgBox("i: " & i & " Buffersize:" & buffersize)
                readwritestructures(i).Buffer = buffer
                readwritestructures(i).BufferLen = buffersize
```

Hier wird immer wieder dieselbe Variable buffer (re)allokiert. Teste bitte einmal:


```
ReDim readwritestructures(i).Buffer(buffersize-1)
                readwritestructures(i).BufferLen = buffersize
```

Dann wird direkt der zur Struktur gehörende Puffer allokiert.
Bei weiteren Fragen einfach melden.

Und verwende doch bitte für Programmausschnitte die Code-Option, ist einfach übersichtlicher.

Viele Grüße


----------



## Sönke Schlüter (25 November 2019)

Guten Abend Rainer,

erstmal Danke für die erste Hilfe.

Der Fehler bleibt erstmal bestehen. Die Hinweise von oben sind eingebaut worden.

Ich konnte den Sachverhalt jetzt schon insoweit eingrenzen, dass es anscheinend mit der RW-STructure zu tun hat (ich habe den Zugriff auf die MLFB-Nummer wiederholt geprüft):
           opc.agl.ReadMLFBNr(out)
            MsgBox("3. SPS-Nummer:" & out) NUMMER WIRD KORREKT AUSGEGEBEN
            Dim buffersize As Integer = 0
            For i = 0 To symbols.Length - 1result = AGL4.Symbolic_GetAccessBufferSize(readwritestructures(i).AccessHandle, buffersize)
                If result <> AGL4.AGL40_SUCCESS Then​Dim errormsg As String = ""
                    AGL4.GetErrorMsg(result, errormsg)
                    MsgBox("buffersizeerror:" & errormsg)​ End If​                MsgBox("i: " & i & " Buffersize:" & buffersize)
opc.agl.ReadMLFBNr(out)
MsgBox("4. SPS-Nummer:" & out)
                'Dim buffer(buffersize - 1) As Byte
                ReDim readwritestructures(i).Buffer(buffersize - 1)
                readwritestructures(i).BufferLen = buffersize​            Next
opc.agl.ReadMLFBNr(out)
MsgBox("5. SPS-Nummer:" & out) NUMMER WIRD KORREKT AUSGEGEBEN​
result = opc.agl.Symbolic_ReadMixEx(readwritestructures)Hier kommt der Fehler​
Ich hatte auch zwischenzeitlich noch versucht gehabt, wie in einem Beispiel von C#, die RW-STructure anders zu definieren. Auch ohne Erfolg.


> Dim readwritestructures(symbols.Length) As AGL4.SymbolicRW
> 'For i = 0 To symbols.Length - 1
> 'readwritestructures(i) = New AGL4.SymbolicRW
> 'Next



So wie ich es sehe, muss irgendetwas noch nicht passen bei der Bestimmung des Buffersizes.

Viele Grüße,

Sönke


----------



## Sönke Schlüter (25 November 2019)

So, Problem gefunden und gelöst !!!

Es lag an was banalem, wie fast vermutet.

Ich hatte in folgender Zeile das RW-Array um ein Feld zu groß gemacht und damit nicht gefüllt später. Anfängerfehler 


> Dim readwritestructures(symbols.Length-1) As AGL4.SymbolicRW



Beim Suchen und Einarbeiten sind mir allerdings zwei kleine Fragen aufgekommen:
1) Ich habe in den AGLink Extensions die Funktionen "CyclicReader" und "NCKCyclicReader" gefunden. Gibt es Anwendungsbeispiele?
2) Die grundsätzliche Vorgehensweise verstehe ich aus dem API-Guide sehr gut. Wofür steht aber "NCK" in dem Fall? Wann wird am besten welche angewendet?

Vielen Dank,

Sönke


----------



## Rainer Hönle (26 November 2019)

Die NCK-Funktionen sind für den Zugriff auf die Sinumerik. Sie sind nicht für den Zufriff auf eine "normale" SPS zu verwenden.
Bei den Beispielen muss ich schauen, bin allerdings heute und morgen in Nürnberg auf der Messe.


----------



## Sönke Schlüter (2 Dezember 2019)

Guten Morgen Herr Hönle,

ich habe am Wochenende (Freizeitprogrammierer  ) mal weiter gemacht.
Ich habe einen Cyclicreader und die Readwritestruktur global erstellt.

```
[LEFT][COLOR=#222222][FONT=Verdana]Public cyclicreader As ICyclicReader[/FONT][/COLOR]
[COLOR=#222222][FONT=Verdana]Public readwritestructures_rw40() As AGL4.DATA_RW40[/FONT][/COLOR][/LEFT]
```


Anschließend die Initialisierung des Readers wie folgt erfolgreich durchgeführt. Im ersten Schritt hier nur mit einem Objektknoten M.01

```
[LEFT][COLOR=#222222][FONT=Verdana]Public Sub start_cyclicreader(ByVal intervall As Integer, ByVal informonlyondatachange As Boolean)
   'Lege erstmal statisch die RWs an
   Try
      opc = New progparas With {
         .verbose = True,
         .agl = AGL4ConnectionFactory.CreateTiaInstance(0, 0, 1)
      }
   Dim result As Integer
   opc.agl.Connect()[/FONT][/COLOR]
[COLOR=#222222][FONT=Verdana]   'Laden der Symbole von der SPS
   Dim rootNodeHandle As IntPtr
   rootNodeHandle = IntPtr.Zero
   result = AGL4.Symbolic_LoadAGLinkSymbolsFromPLC(opc.agl.ConnNr, opc.roothandle)
   If result = AGL4.AGL40_SUCCESS Then
      MsgBox("erfolgreich geladen")
   Else 
      MsgBox("Fehler beim laden : " & result)
      Dim errortext As String = ""
      AGL4.GetErrorMsg(result, errortext) 
      MsgBox("Fehler: " & errortext)
   End If
   Dim symbols(0) As String
   symbols(0) = "M0.1"
   ReDim readwritestructures_rw40(symbols.Length - 1)[/FONT][/COLOR]
[COLOR=#222222][FONT=Verdana]   Dim errorposition As Integer = 0[/FONT][/COLOR]
[COLOR=#222222][FONT=Verdana]   For i = 0 To symbols.Length - 1
      result = AGL4.Text2DataRW(symbols(i), readwritestructures_rw40(i))
      If result = AGL4.AGL40_SUCCESS Then
      MsgBox("i: erfolgreich geladen")
   Else
      MsgBox("Fehler beim laden i: " & result)
      Dim errortext As String = ""
      AGL4.GetErrorMsg(result, errortext)
      MsgBox("Fehler: " & errortext)
      End If
   Next[/FONT][/COLOR][/LEFT]
```

Das funktioniert soweit auch fehlerfrei und läuft durch.
Allerdings komme ich jetzt nicht recht weiter.
Mit "Dim handle As Integer = 0" und  "result = AGL4.InitCyclicRead(opc.agl.ConnNr, 1000, True, readwritestructures_rw40, handle, 1000)" gibt die Fehlermeldung "*Funktion wird nicht unterstützt*" zurück.

Das einzige Beispiel welches ich in den Samples finden konnte, befindet sich in der Datei "NCK-Samples 2010". Hier wird ein Cyclicreader allerdings komplett anders erstellt.
Die dort genannte Funktion " m_cyclicReader = base.Connection.Aglink.CreateCyclicNCKReader();" finde ich weder in den Referenzhandbüchern, noch im API-Guide.

Über eine kleine Hilfe wäre ich dankbar.
Ich möchte gerne ähnlich wie im Beispiel über ein "Ondatareceived-Ereignis" zyklisch die PLC-Änderungen verarbeiten.

Viele Grüße,
Sönke Schlüter


----------



## Rainer Hönle (2 Dezember 2019)

Was für eine SPS ist den angeschlossen (MLFBNr)? Funktioniert das Lesen und ggf. Schreiben ohne CyclicReader?
Bitte zukünftig Codeausschnitte als Code (das #-Zeichen in der Toolbar) kennzeichnen. Dies erhöht die Lesbarkeit.
Und wie gesagt, die NCK-Funktionen beim Zugriff auf eine SPS total vergessen. Diese sind nur für eine Sinumerik-Steuerung!


----------



## Rainer Hönle (2 Dezember 2019)

Wennes sich um eine S7-1200 oder S7-1500 handelt, dann unterstützt die das CyclicRead nicht. Hier hilft nur pollen und auf Wertänderung prüfen.


----------



## Sönke Schlüter (2 Dezember 2019)

Guten Abend,

dann kommen wir der Lösung näher. 
Also, Lesen und Schreiben funktioniert über die entsprechenden Funktionen. Leider handelt es sich um eine S7-1500. 
Die Information, dass der Cyclicreader nicht funktioniert, habe ich nirgendwo gefunden.

Gibt es ein Code-Schnipsel zum Pollen? Hab dort in den Beispielen auch nichts finden können. Sonst mache ich mich an die Arbeit.

Viele Grüße,

Sönke

P.S.: #-Zeichen jetzt gefunden, ändere alten Beitrag für die Nachwelt noch ab. Danke!


----------



## Rainer Hönle (2 Dezember 2019)

Der Code sieht doch gleich viel besser aus! 
Von den 29 mitgelieferten .net-Beispielen passt keines?


----------



## Sönke Schlüter (2 Dezember 2019)

Guten Abend,

ich habe eben nochmal alle 29 durchgeschaut.
Es wird nur bei zweien zyklisch zugegriffen. Das aber mit Cyclicreader und NCK.
Wenn die Frage rhetorisch war, dann bitte für mich den Wink mit dem Zaunpfahl

Ansonsten habe ich jetzt mal 80% von nem Polling fertig. Werde morgen Abend weitermachen


----------



## Rainer Hönle (3 Dezember 2019)

Die Frage zielte nicht auf den CyclicReader, sondern auf das Pollen.


----------



## Sönke Schlüter (3 Dezember 2019)

Ja, klar.
Ich habe zum Pollen ohne NCK / Cyclicreader in den Samples Nichts gefunden.
Aber wie gesagt... kein Spezialist. Lasse mich gerne mit dem Zaunpfahl hinweisen im Zweifel. Habe alle Beispiel durchgeschaut. Die zyklischen Beispiele verwenden alle die cyclicreader.cs und sind damit nicht anwendbar.


----------



## Rainer Hönle (3 Dezember 2019)

Nach erfolgreichem Lesen einen Timer starten und, falls in der Zwischenzeit nicht abgebrochen oder das Programm beendet werden soll, den Leseauftrag erneut starten.
Wenn nicht erfolgreich gelsen wurde, dann die Fehlerbehandlung durchführen. Hierbei sowohl den Rückgabewert der Lesefunktion als auch die Rückgabewerte der einzelnen Variablen beachten. Es könnte ja sein, dass eine einzelne Variable gar nicht existoert und deshalb nicht gelesen werden kann.


----------

