# libnodave anfänger



## dannyli (13 Mai 2009)

Hallo zusammen

Erstmal grosses Lob ist ein echt klasse Forum hier.......

Habe im Rahmen meiner Bachelorarbeit die Aufgabe verschiedene DB aus einer 
S7 CPU 314 2DP auszulesen und in eine SQL DB zu schreiben.Dies scheit ja laut den Beiträgen mit libnodave möglich zu sein. Da ich im Bereich Hochsprachen so gut wie keine Ahnung habe versuche ich ich mich nun in das Thema einzulesen:

Im Ordener doc\gettingStarted unter What the programm can do werden verschiedene Optionen beschrieben um über das Testprogramm mit der CPU zu kommunizieren If you specify the option -w........ usw. 
Will in VB2008 schreiben

Hier meine Fragen: -kann ich in vb2008 schreiben? ist das testprogramm im dot.net ordener unter vb das richtige für mich zum testen?Wo kann ich die o.g. Optionen einstellen?
Wäre weiterhin dankbar wenn ich ein paar allgemeine Informationen über das strukturieren eines solchen Programms bekommen könnte bzw. wie ich libnodave im Programm einsetze.

so denke da reicht erstmal 
vielen dank für eure Bemühungen schon mal vor ab.....

mfG
*dannyli
*


----------



## Human (14 Mai 2009)

Hallo dannyli,

ich arbeite seit ca. 2 Jahren mit libnodave und kann mit voller Überzeugung sagen, dass das was du vorhast wirklich so funktioniert!

Als erstes würde ich hingehen und zuerst einmal ein Testprogramm schreiben, mit dem du einmal die Kommunikation aufbauen, abbauen und Werte aus der SPS lesen bzw. schreiben kannst. Das kannst du dann ja so lange erweitern bis es dann auch noch die Daten in die Datenbank schreibt und dann zum Schluss das ganze zu automatisieren.

Ich persönlich programmiere meine Programme bevorzugt mit Delphi, davon gibt es auch eine kostenlose Version (Turbo Delphi) und dafür ist auch eine Komponente dabei, mit der das Arbeiten mit libnodave relativ einfach wird, ob und wie es mit VB2008 funktioniert kann ich dir nicht sagen.


----------



## dannyli (15 Mai 2009)

Hallo Human 

Erstmal danke für deine Antwort. Habe versucht ein kleines Programm zu erstellen mit dem ich erstmal eine Verbindung zur SPS herstellen kann. bekomme nun angezeigt libnodave.doserialType is not defined. habe die libnodave .dll schon in mein system 32 kopiert. was muss ich machen um die libnodaves zu definieren?


----------



## Ralle (15 Mai 2009)

Ich mu0ß mal blöd nachfragen. Ist VB2008 nicht .Net? Da gabs dann doch noch eine Wrapper-DLL.


----------



## dannyli (15 Mai 2009)

Hallo Ralle

wie gesagt bin ich blutiger Amfänger was Hochsprachen betrifft. Programmiere mit MS Visual Basic Express Edition. Habe für meine ersten versuche ein älteres Beispiel von earny verwendet siehe:
http://www.sps-forum.de/showthread.php?t=24391 dieses Beispiel konnte ich soweit nachvollziehen und eine eigene Form in 2008 erstellen. mit der ich zunächst mal eine Kommunikation aufbauen will. hier mal den code den ich bis jetzt geschrieben habe:

Option Explicit On
Option Strict Off
Public Class Form1
    Dim localMPI As Integer = 0, plcMPI As Integer = 2
    Dim fds As libnodave.daveOSserialType
    Dim di As libnodave.daveInterface
    Dim dc As libnodave.daveConnection
    Dim res As Integer = 1
    Private Declare Function daveGetU8from Lib "libnodave.dll" (ByRef buf As Byte) As Byte
    Private Declare Function daveGetS8from Lib "libnodave.dll" (ByRef buf As Byte) As Short
    Private Declare Function daveGetS16from Lib "libnodave.dll" (ByRef buf As Byte) As Short
    Private Declare Function daveGetS32from Lib "libnodave.dll" (ByRef buf As Byte) As Integer
    Private Declare Function daveGetFloatfrom Lib "libnodave.dll" (ByRef buf As Byte) As Single

    Private Sub Timer1_Tick(ByVal sender As System.Object, _
    ByVal e As System.EventArgs) Handles Timer1.Tick
        Select Case fds.rfd  'Portstatus - lesen
            Case 0
                txtFDS.Text = "Nicht verbunden"
                txtFDS.BackColor = Color.Orange
            Case Is > 0
                txtFDS.Text = "OK"
                txtFDS.BackColor = Color.Green
            Case Is < 0
                txtFDS.Text = "Fehler"
                txtFDS.BackColor = Color.Red
        End Select
        Select Case res    'Adapterstatus - lesen
            Case 0
                txtRES.Text = "OK"
                txtRES.BackColor = Color.Green
            Case Is < 0
                txtRES.Text = "Fehler LibNoDave"
                txtRES.BackColor = Color.Red
            Case Is > 0
                txtRES.Text = "Fehler CPU"
                txtRES.BackColor = Color.Orange
        End Select
    End Sub

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        ByVal e As System.EventArgs) Handles Button1.Click
        If rdbIP.Checked = True Then Call ISO_TCP()
        If rdbCOM.Checked = True Then Call MPI()
    End Sub
    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        ByVal e As System.EventArgs) Handles Button2.Click
        di.disconnectAdapter()
        libnodave.closePort(fds.rfd)
        fds.rfd = 0
        res = 1
        di = Nothing
    End Sub
    Public Sub ISO_TCP()
        Dim IP As String
        IP = cbxIP.Text
        If IP <> "" Then 'Kontrolliert, ob der Bediener eine Eingabe gemacht hat
            fds.rfd = libnodave.openSocket(102, IP) 'Portstatus - lesen
            fds.wfd = fds.rfd 'Portstatus schreiben = Portstatus - lesen
            di = New libnodave.daveInterface(fds, "Mein Interface", localMPI, _
            libnodave.daveProtoISOTCP, libnodave.daveSpeed187k)
            di.setTimeout(1000000)
            res = di.initAdapter
            If res = 0 Then       'initAdapter OK
                ' Rack und Slot spielen keine Rolle bei diesem Protokoll
                dc = New libnodave.daveConnection(di, plcMPI, 0, 2)
                res = dc.connectPLC()
            End If
        Else
            MsgBox("Bitte Comport angeben", MsgBoxStyle.Information, "Fehler")
        End If
    End Sub

Die rot markierten bereiche werden als nicht definiert deklariert weiss du oder jemand anderes damit anzufangen???
mfG


----------



## Human (15 Mai 2009)

Fdür mich sieht das so aus, als wenn das aus irgendeiner anderen Scriptdatei oder Klasse kommt.

Ich bin mir da jetzt nicht ganz sicher, aber es müsste doch so eine Funktion geben, mit der du nach der Deklaration suchen kannst.

Mach das Originalprojekt auf und such mal danach, das wird da sicher irgendwo drin sein.


----------



## Ralle (15 Mai 2009)

Ich seh das ähnlich wie Human. daveOSserialType findet sich z.Bsp. in der libnodave.net.dll. Keine Ahnung, wie die eigentlich bei VB2008 eingebunden wird. Kann sein, daß hier noch in irgendwas in VB eingetragen werden muß.


----------



## dannyli (15 Mai 2009)

also die definition scheit funktioniert zu haben, falls mal jemand das problem haben sollte:

rechte Maustaste auf Projektname dann auf verweis hinzufügen, reier durchsuchen, im libnodave ordner order dot.net die libnodave.net.dll hinzufügen.

habe jetz noch ein sytax problem was bei vb 2005 nicht aufgetreten ist, gibt es da eine möglichkeit das anzupassen?


----------



## Ralle (15 Mai 2009)

Lies mal das hier (im hinteren Teil wird es für dich interessant), vielleicht hängt es damit zusammen:

http://www.sps-forum.de/showthread.php?t=26868&highlight=libnodave

PS: Aber ne, eigentlich eher nicht.


----------



## Human (15 Mai 2009)

Meine Kristallkugel scheint gerade kaputt zu sein, kannst du vielleicht noch sagen an welcher Stelle von der Syntaxfehler auftritt?


----------



## dannyli (15 Mai 2009)

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
ByVal e As System.EventArgs) Handles Button1.Click
If rdbIP.Checked = True Then Call ISO_TCP()
If rdbCOM.Checked = True Then Call MPI()
End Sub
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
ByVal e As System.EventArgs) Handles Button2.Click
di.disconnectAdapter()
libnodave.closePort(fds.rfd)
fds.rfd = 0
res = 1
di = Nothing
End Sub


an den markierten stellen tritt er auf.....

weiterhin habe ich in folgenden codeabschnitt noch ein problem mit der laut VB2008 Handles Klausel diese erfordert eine witheventsvariable, die im enthaltenen Typ oder einem seiner Basistypen definiert wird

Private Sub Timer1_Tick(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Timer1.Tick


meine letzten drei fehler bis zum ersten Test.......

Gruss dannyli


----------



## Ralle (15 Mai 2009)

dannyli schrieb:


> Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
> ByVal e As System.EventArgs) Handles Button1.Click
> If rdbIP.Checked = True Then Call ISO_TCP()
> If rdbCOM.Checked = True Then Call MPI()
> ...



Verstehe ich gerade nicht.
Die ganze Zeile mit dem rot markierten ByVal ist doch Käse. Da fehlt doch ein Stück Code vorher!


----------



## dannyli (15 Mai 2009)

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
ByVal e As System.EventArgs) Handles Button1.Click
If rdbIP.Checked = True Then Call ISO_TCP()
If rdbCOM.Checked = True Then Call MPI()
End Sub
Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
ByVal e As System.EventArgs) Handles Button2.Click
di.disconnectAdapter()
libnodave.closePort(fds.rfd)
fds.rfd = 0
res = 1
di = Nothing
End Sub


an den markierten stellen tritt er auf.....

weiterhin habe ich in folgenden codeabschnitt noch ein problem mit der laut VB2008 Handles Klausel diese erfordert eine witheventsvariable, die im enthaltenen Typ oder einem seiner Basistypen definiert wird

Private Sub Timer1_Tick(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Timer1.Tick


meine letzten drei fehler bis zum ersten Test.......

Gruss dannyli


----------



## dannyli (15 Mai 2009)

Hab den code aus dem vb2005 projekt von earny übernommen.
könntest du mir vieleicht einen hinweis geben was vorher noch kommen muss. verstehe das so, das wenn ich den button verbinden betätige und der jeweilige ratio button angewählt ist die entsprechende verbindung aufgebaut wird...


----------



## dannyli (15 Mai 2009)

Private Sub Button1_Click(ByVal sender As System.Object,_
ByVal e As System.EventArgs) Handles Button1.Click
If rdbIP.Checked = True Then Call ISO_TCP()
If rdbCOM.Checked = True Then Call MPI()
End Sub
Private Sub Button2_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button2.Click
di.disconnectAdapter()
libnodave.closePort(fds.rfd)
fds.rfd = 0
res = 1
di = Nothing
End Sub


so muss es heissen dann sind auch die fehler weg sorry


----------



## Ralle (15 Mai 2009)

dannyli schrieb:


> Private Sub Button1_Click(ByVal sender As System.Object,_
> ByVal e As System.EventArgs) Handles Button1.Click
> If rdbIP.Checked = True Then Call ISO_TCP()
> If rdbCOM.Checked = True Then Call MPI()
> ...



Sag ich doch


----------



## dannyli (15 Mai 2009)

so das Timerproblem ist auch gelöst......

und das schlimmste ist alle Programmierer ausser haus weder Crossoverkabel noch MPI schnittstelle.....zum testen  naja glaub das ist das zeichen um ins wochenende zu starten...

vielen dank ralle und human für eure unterstützung.......


----------



## Ralle (15 Mai 2009)

dannyli schrieb:


> so das Timerproblem ist auch gelöst......
> 
> und das schlimmste ist alle Programmierer ausser haus weder Crossoverkabel noch MPI schnittstelle.....zum testen  naja glaub das ist das zeichen um ins wochenende zu starten...
> 
> vielen dank ralle und human für eure unterstützung.......



Ich mach das mit einem normalen NW-Kabel, kein Cross-Over. Hängt vielleicht vom Laptop ab?

Schönes WE!


----------



## Human (15 Mai 2009)

Jaja, über die Cross-Over-Kabel kann ich auch ein Liedchen singen... ich hatte mal 2 bis es ein Kollege mitbekommen hat... *ROFL*

Schönes Wochenende!


----------



## dannyli (19 Mai 2009)

hallo leute
habe es gestern erfolgreich geschafft eine verbindung zu der sps herzustellen.
nun habe ich noch ein paar fragen. ich will aus mehreren DB immer wieder die gleichen werte auslesen. im doc ordner der libnodave gibts ja readbytes ich verstehe auch soweit den aufbau ,aber was hat es mit dem buffer auf sich? ist das so eine art speicher für die Daten die libnodave von der sps holt? weiterhin wird in anderen Beiträgen was von get methoden erwähnt was bedeutet das? und zu guter letzt würde mich noch interessieren wie ich das zyklische auslesen realisieren könnte vieleicht mit einer do/while schleife? wie gesagt sind meine Anfäge in hochsprchen programmierung.....

Grüsse dannyli


----------



## Ralle (19 Mai 2009)

dannyli schrieb:


> hallo leute
> habe es gestern erfolgreich geschafft eine verbindung zu der sps herzustellen.
> nun habe ich noch ein paar fragen. ich will aus mehreren DB immer wieder die gleichen werte auslesen. im doc ordner der libnodave gibts ja readbytes ich verstehe auch soweit den aufbau ,aber was hat es mit dem buffer auf sich? ist das so eine art speicher für die Daten die libnodave von der sps holt? weiterhin wird in anderen Beiträgen was von get methoden erwähnt was bedeutet das? und zu guter letzt würde mich noch interessieren wie ich das zyklische auslesen realisieren könnte vieleicht mit einer do/while schleife? wie gesagt sind meine Anfäge in hochsprchen programmierung.....
> 
> Grüsse dannyli



Ja readbytes oder auch readmanybytes holt die Daten aus der SPS und legt sie in Buf ab. Auf die Größe von Buf aufpassen!)
Ich bau dann die Daten aus dem Buffer selber so zusammen, wie ich sie brauche (INT, DINT, STRING, REAL, BOOL), mit den Get-Methoden kann man das Libnodave machen lassen, wenn ich das richtig erinnere.
Ich habe einen eigenen Thread für das Lesen/Schreiben der Daten angelegt, in der Komponente für Delphi wird das auch so gehandhabt, da man sich ansonsten u.U. die Bedienoberfläche ausbremst und diese teilweise nicht mehr bedienbar ist oder auch hakelt. Man muß dann zwar mit Synchonisier-Methoden arbeiten, um dann Daten Online anzuzeigen, aber das hat sich als rel. problemlos erwiesen. Dieser Thread ist bei mir im Prinzip eine Endlosschleife, die alle beteiligten SPS nacheinnander anfragt und die Daten liest/schreibt.


----------



## dannyli (19 Mai 2009)

hallo ralle hab grad irgendwie nen hänger hier mal ein stück code:

Private Sub Timer2_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer2.Tick

        Dim buf(0) As Byte
        If fds.rfd > 0 Then
            res = dc.readBytes(libnodave.daveDB, 1, 0, 144, buf)
        End If
    End Sub


dieser timer fragt zyklisch den db ab welcher 144 Bytes besitzt. da ja im doc steht man soll so grosse datenpakete wie möglich abholen ist mir nun nicht so wirklich klar wie ich die daten im db wieder in die einzelnen stücke zerlegen kann um sie dann in eine sql db zu schreiben .


----------



## Ralle (19 Mai 2009)

buf(0) ist doch sicher zu klein oder? Entweder gelich in der richtigen Größe oder mit redim nach der Definiton nochmals verändern.

Ich nehme die einzelnen Bytes dann aus dem Array Buf[0...irgendwas] und baue mir die zahlen selbst zusammen. Die Getfunktionen sollten das für dich tun, damit hab ich mich noch nicht befaßt. Entweder man gibt an woher die die Daten nehmen oder sie erhöhen immer einen Zeiger um den ensprechenden Betrag (4 bei Real). Lies das mal in der Dok nach, evtl. findet sich hier im Forum was dazu, kommt mir doch ein wenig bekant vor. Ich muß in Delphi in der Funktion einen Pointer übergeben, weiß nicht, wie das in VB aussieht. War da nicht ein Beispiel bei libnodave dabei?


----------



## Question_mark (19 Mai 2009)

*Crossover Kabel*

Hallo,



			
				Ralle schrieb:
			
		

> Ich mach das mit einem normalen NW-Kabel, kein Cross-Over. Hängt vielleicht vom Laptop ab?



Eher nicht vom Laptop, sondern von dem verbauten NIC (Network Interface Card) ab. Moderne NIC's haben ein integriertes "Autosense" und können automatisch erkennen, ob gedreht werden muss. Und das macht der NIC dann auch automatisch. Irgendwann wird es keine Crossover Kabel mehr geben.

Gruß

Question_mark


----------



## Question_mark (19 Mai 2009)

*Es gibt gute Gründe, warum ich VB nicht besonders mag*

Hallo,



			
				Ralle schrieb:
			
		

> Ich muß in Delphi in der Funktion einen Pointer übergeben, weiß nicht, wie das in VB aussieht.



VB und Zeiger sind zwei getrennte Welten, vielleicht hilft das hier :

http://www.aboutvb.de/khw/artikel/khwptrtostrg.htm

Man muss da in VB schon etwas tricksen ..

Gruß

Question_mark


----------



## Rainer Hönle (20 Mai 2009)

Pointer sind in VB nicht wirklich kompliziert. Der Parameter muss nur mit ByRef deklariert sein. Und den Zeiger auf ein Array übergibt man dann

```
Dim a(100) as Long
x = Func(a(0))
```
Das ist alles.


----------



## dannyli (20 Mai 2009)

hallo zusammen

danke erstmal für eure antworten. da ich erst seit gut 2 wochen programmiere fällt es mit schwer eure vorschläge zu verstehen.
ich habe doch in meinen DB verschiedene Structs angelegt in diesen befinden sich verschiedene Informationen die als stings oder bool abgelegt werden.mit get funktionen kann ich ja nur max 4 byte holen wenn ich das so richtig verstanden habe oder?,ich lese im moment mit read aber die gesamten 144 bytes aus und weiss nicht wie ich diese in meine sql bringen kann. die infos im db sind doch so etwas wie ein Byte array oder? kann ich dieses nicht in einen string wandeln und mir aus dem die entsprechenden infos rausholen? oder hab ich eine möglichkeit die mir libnodave bietet übersehen?......

gruss dannyli


----------



## Ralle (20 Mai 2009)

Wenn du die Struktur des DB kennst, dann ist es doch gut. Du kannst dann die 144 gelesenen Byte genau so wieder zusammenbauen, wie sie im DB abgelegt sind. Die Getfunktionen helfen dir schon mal bei DINT, Float etc. Die Strings sind ja auch nicht der Hit. Du weiß, daß ein String im DB bei DBB20 anfängt. Die ersten beiden Byte enthalten die Längeninfo. Byte 0 --> Max. Länge, Byte 1 aktuelle Länge des String. In Byte 1 steht z.Bsp eine 10. Dann kannst du also auf Byte 2,3,4,5,6,7,8,9,10,11 zugreifen und diese zu einem String zusammenbauen (z.Bsp. concat in Delphi). Wenn dein Buffer also mit 0 beginnt wären das Buf(22) bis Buf(31). Wie gesagt, zu den Getfunktionen kann ich nicht viel sagen, ich bau mir auch die anderen Typen gleich selbst zusammen.


----------



## dannyli (25 Mai 2009)

hallo hier bin ich mal wieder

ich habe mein programm jetzt soweit das ich meinen db zylisch auslesen kann mit davereadmanybytes. habe jetz mal einen db erstellt der aus einem string besteht mit 20 zeichen. wenn ich jetzt was in den string schreibe z.b. einen wert den ich aus einen barcode gelesen habe oder eben irgent eine zeichenkette z.B. 'abcd1234' bekomme ich aber nur sehr grosse zahlenwerte angezeigt denke mal integer mein problem ist nun wie ich die werte wandeln kann oder wie ralle so schön sagt zusammen setzen kann habe schon alles mögliche versucht aber keine chance.vieleicht kann mir jemand weiter helfen?

gruss dannyli


----------



## Ralle (25 Mai 2009)

Na ja, ich arbeite nicht mit VB, daher kann ich dir nicht so richtig sagen, wie du in VB deine Variablen zusammenbaust.

Aber mal vom Prinzip:

http://www.asciitable.com/

Jedes Byte des String repräsentiert ein Zeichen im Char-Code. Step7 hat noch einen Kopf von 2 Byte vor dem String, in dem steht die definierte und die tatsächliche Länge des String.

Nun kannst du also hergehen, Byte 0 ist die definierte Länge (soviele Byte sollten in deinem DB für den String angelegt sein), Byte 1 ist die tatsächliche Länge (soviele Byte werden aktuell von deinem String belegt).

Du suchst dir eine Funktion in VB, die Zeichen oder Strings verkettet. Dann definierst du dir einen String, liest dein Array (Buf) bei den entsprechenden Stellen byteweise aus und verkettest dieses Byte mit dem definierten String.  
Wie gesagt, VB ist nicht mein Ding .Net schon gar nicht, also keine Ahnung, wie das dort genau definiert ist. Ich denke aber im Netz findest du zu diesem Thema (verketten oder addieren oder zudammenfügen von Strings) sicher auch eine ganze Menge.


----------

