# Verwendung DotNetSiemensPLCToolBoxLibrary von Jochen Kühner



## hanjo (16 März 2011)

Hallo Leute

Zur Verwendung der „DotNetSiemensPLCToolBoxLibrary“von J. Kühne habe ich mindestens zwei Fragen.
Ich verwende Visualstudio 2010 und arbeite mit Visualbasic.

Frage 1
Ich möchte eine vorgegeben Byteanzahl aus der SPS in ein Bytearray einlesen um die eingelesenen Daten anschließend in verschiedene Datenformate zu konvertieren.
Die Sub-Routine „Test()“ soll die Aufgabe realisieren.
Allerdings funktioniert sie nicht. Beim Lesen der Bytes aus der SPS in das Bytearray tritt ein Fehler auf.
Was stimmt in dem Code nicht ?


Sub Test()
'Dieses Testmodul soll 6 Merkbytes ab Merkerbyte 500 in ein Bytearray lesen

'Die Verbindung zur SPS funktioniert und wurde mit dem Aufruf des Konfigurationsmenü eingestellt und getestet
'So wurde die Verbindung aktiviert:
'Konfigurationsmenü Verbindung 1
'Configuration.ShowConfiguration("SPS1", True)
'PLCCon1.Configuration.ConnectionName = "SPS1"
'Mit "PLCCon1.Connect()"

Dim aVar As New PLCTag
Dim Bytearray(100) As Byte
Dim S8 As Byte
Dim S16 As Short
Dim S32 As Integer
Dim Real As Single

aVar.ByteAddress = 500
aVar.BitAddress = 0
aVar.DatablockNumber = 200

aVar.LibNoDaveDataSource = TagDataSource.Flags
aVar.LibNoDaveDataType = TagDataType.ByteArray
aVar.ArraySize = 6
MsgBox("Init ok")

PLCCon1.ReadValuesFromByteArray(aVar, Bytearray, 0)
MsgBox("Read ok")

S8 = libnodave.getS8from(Bytearray, 0)
S16 = libnodave.getS16from(Bytearray, 0)
S32 = libnodave.getS32from(Bytearray, 0)
Real = libnodave.getFloatfrom(Bytearray, 0)

MsgBox("S8=" & S8 & " S16=" & S16 & " S32=" & S32 & " Real=" & Real)

aVar = Nothing
End Sub


Frage 2

Um ein Byte in die SPS zu schreiben, verwende ich folgenden Programmteil. 
Dieser Programmteil funktioniert. – die Textbox „Me.txt_Wert1“ enthält z.B. „23“ – die 23 wird zur SPS übertragen.
Das Array Adr ist ein String-Array. 
- Adr(0) enthält die Zeichenkette “500”, die Adr(1) enthält die Zeichenkette “0”. 
- DBNr ist ein String und enthält „200“.
- Die Variable „Bereich“ = „Merker“
- Der String „VarTyp“ = Byte“

If VarTyp = "Byte" Then
Dim Var As New Communication.PLCTag

Var.ByteAddress = CInt(Adr(0))
Var.BitAddress = CInt(Adr(1))
Var.DatablockNumber = CInt(DBNr)
Var.LibNoDaveDataType = TagDataType.Byte
If Bereich = "Daten" Then Var.LibNoDaveDataSource = TagDataSource.Datablock
If Bereich = "Eingänge" Then Var.LibNoDaveDataSource = TagDataSource.Inputs
If Bereich = "Ausgänge" Then Var.LibNoDaveDataSource = TagDataSource.Outputs
If Bereich = "Merker" Then Var.LibNoDaveDataSource = TagDataSource.Flags

Value = Me.txt_Wert1.Text
Var.ParseControlValueFromString(Value)
PLCCon1.WriteValue(Var)
'Me.txt_Wert1.Text = Var.Value
Var = Nothing
End If

Nun meine Frage :

Wie muss der Programmteil aussehen, wenn ein REAL-Wert zur SPS übertragen werden soll.
Der folgende Programmteil funktioniert nicht – er überträgt immer eine 0.0.
Welcher Wert muss in der Textbox stehen „Me.txt_Wert1.Text“– damit die Übertragung einer REAL-Variablen in die SPS erfolgreich ist?
Das Array Adr ist ein String-Array. 
- Adr(0) enthält die Zeichenkette “500”, die Adr(1) enthält die Zeichenkette “0”. 
- DBNr ist ein String und enthält „200“.
- Die Variable „Bereich“ = „Merker“
- Der String „VarTyp“ = REAL“

If VarTyp = "REAL" Then
Dim Var As New Communication.PLCTag

Var.ByteAddress = CInt(Adr(0))
Var.BitAddress = CInt(Adr(1))
Var.DatablockNumber = CInt(DBNr)
Var.LibNoDaveDataType = TagDataType.Float
If Bereich = "Daten" Then Var.LibNoDaveDataSource = TagDataSource.Datablock
If Bereich = "Eingänge" Then Var.LibNoDaveDataSource = TagDataSource.Inputs
If Bereich = "Ausgänge" Then Var.LibNoDaveDataSource = TagDataSource.Outputs
If Bereich = "Merker" Then Var.LibNoDaveDataSource = TagDataSource.Flags

Value = Me.txt_Wert1.Text
Var.ParseControlValueFromString(Value)
PLCCon1.WriteValue(Var)
Me.txt_Wert1.Text = Var.Value
Var = Nothing
End If


----------



## Jochen Kühner (16 März 2011)

Hallo erst mal.

Das lesen funzt nicht da du die Funktion ReadValuesFromByteArray(aVar, Bytearray, 0) verwendest. Diese Funktion ist dazu da um den Tag mit Werten aus einem ByteArray zu befüllen das du z.B. per TCP direkt auf den PC schickst.

du kannst den Tag einfach mit
PLCCon1.ReadValue(aVar)
einlesen.

Da du aber Verschiedene Variablen willst, würde Ich das ganz anderst angehen.

Du legst dir eine Liste mit verschiedenen PLCTags an, und liest diese mit PLCCon1.ReadValues ein.

An meiner lib soll ja der Vorteil sein, das du dieses zerlegen eines ByteStreams in die einzelnen Variablen nicht mehr machen musst!

Beispielcode:


```
Dim Tags As New List(Of PLCTag)

        Dim val1 As New Communication.PLCTag("MB500")
        val1.LibNoDaveDataType = TagDataType.Byte
        Tags.Add(val1)

        Dim val2 As New Communication.PLCTag("MW501")
        val1.LibNoDaveDataType = TagDataType.Int
        Tags.Add(val2)

        Dim val3 As New Communication.PLCTag("MD503")
        val1.LibNoDaveDataType = TagDataType.Dint
        Tags.Add(val3)

        Dim val1 As New Communication.PLCTag("MD507")
        val1.LibNoDaveDataType = TagDataType.Float
        Tags.Add(val4)
        PLCCon1.ReadValues(Tags)
```


----------



## hanjo (16 März 2011)

*Danke für die Anwort*

Vielen Dank für die Anwort - ich werde es morgen in beiden Varianten testen

Viele Güße hanjo


----------



## hanjo (16 März 2011)

*Zur 2. Frage*

Wie gesagt - den ersten Teil werde ich testen.

Die zweite Frage würde ich gern noch mal wiederholen - dabei ging es um das Schreiben eines Real-Wertes.

Frage 2

Um ein Byte in die SPS zu schreiben, verwende ich folgenden Programmteil. 
Dieser Programmteil funktioniert. – die Textbox „Me.txt_Wert1“ enthält z.B. „23“ – die 23 wird zur SPS übertragen.
Das Array Adr ist ein String-Array. 
- Adr(0) enthält die Zeichenkette “500”, die Adr(1) enthält die Zeichenkette “0”. 
- DBNr ist ein String und enthält „200“.
- Die Variable „Bereich“ = „Merker“
- Der String „VarTyp“ = Byte“

If VarTyp = "Byte" Then
Dim Var As New Communication.PLCTag

Var.ByteAddress = CInt(Adr(0))
Var.BitAddress = CInt(Adr(1))
Var.DatablockNumber = CInt(DBNr)
Var.LibNoDaveDataType = TagDataType.Byte
If Bereich = "Daten" Then Var.LibNoDaveDataSource = TagDataSource.Datablock
If Bereich = "Eingänge" Then Var.LibNoDaveDataSource = TagDataSource.Inputs
If Bereich = "Ausgänge" Then Var.LibNoDaveDataSource = TagDataSource.Outputs
If Bereich = "Merker" Then Var.LibNoDaveDataSource = TagDataSource.Flags

Value = Me.txt_Wert1.Text
Var.ParseControlValueFromString(Value)
PLCCon1.WriteValue(Var)
'Me.txt_Wert1.Text = Var.Value
Var = Nothing
End If

Nun meine Frage :

Wie muss der Programmteil aussehen, wenn ein REAL-Wert zur SPS übertragen werden soll.
Der folgende Programmteil funktioniert nicht – er überträgt immer eine 0.0.
Welcher Wert muss in der Textbox stehen „Me.txt_Wert1.Text“– damit die Übertragung einer REAL-Variablen in die SPS erfolgreich ist?
Das Array Adr ist ein String-Array. 
- Adr(0) enthält die Zeichenkette “500”, die Adr(1) enthält die Zeichenkette “0”. 
- DBNr ist ein String und enthält „200“.
- Die Variable „Bereich“ = „Merker“
- Der String „VarTyp“ = REAL“

If VarTyp = "REAL" Then
Dim Var As New Communication.PLCTag

Var.ByteAddress = CInt(Adr(0))
Var.BitAddress = CInt(Adr(1))
Var.DatablockNumber = CInt(DBNr)
Var.LibNoDaveDataType = TagDataType.Float
If Bereich = "Daten" Then Var.LibNoDaveDataSource = TagDataSource.Datablock
If Bereich = "Eingänge" Then Var.LibNoDaveDataSource = TagDataSource.Inputs
If Bereich = "Ausgänge" Then Var.LibNoDaveDataSource = TagDataSource.Outputs
If Bereich = "Merker" Then Var.LibNoDaveDataSource = TagDataSource.Flags

Value = Me.txt_Wert1.Text
Var.ParseControlValueFromString(Value)
PLCCon1.WriteValue(Var)
Me.txt_Wert1.Text = Var.Value
Var = Nothing
End If


----------



## Jochen Kühner (16 März 2011)

Sollte nun auch gehen.

War noch ein Fehler in meiner Lib. 
Hatte bei der Funktion ParseControlvalueFromString Float vergessen!


----------



## hanjo (16 März 2011)

*Herzlichen Dank*

Hab mir die geänderte Bibliothek heruntergeladen und versuch es mit dem Schreiben des Float-Wertes morgen an der SPS.

Vielen Dank !


----------



## hanjo (17 März 2011)

*Nach dem versprochenem Test*

*Punkt 1* *- Wie versprochen habe ich heute das Lesen und Schreiben von einzelnen Variablen in verschiedenen Formaten getestet.*
SPS : S7-400 CPU417-3
CP : TCP-Verbindung

Das Ergebnis ist in der Übersicht Bild "Ergebnis" im Anhang enthalten
Bei den rot markierten Positionen traten Fehler beim Lesen bzw. Schreiben auf.

*Punkt 2 – Wie von Jochen vorgeschlagen habe ich verschiedene Variablen in einer Liste des Typs PLCTag zusammengefasst und aus der SPS gelesen bzw. geschrieben.*
Leider hat weder das Lesen noch das Schreiben der Liste funktioniert.
Hier auszugsweise der Code:
Die Routine „Sub InitListe“ füllt die Variablenliste „TagList“ mit PLCTag Variablen
Sub InitListe(ByRef TagList As List(Of PLCTag))
'Tags entspricht einer Liste von PLCTags
'Tags = Nothing

Dim val1 As New PLCTag
'BOOL-Variable M500.0 
val1.LibNoDaveDataSource = TagDataSource.Flags
val1.LibNoDaveDataType = TagDataType.Bool
val1.DatablockNumber = 200
val1.ByteAddress = 500
val1.BitAddress = 0
TagList.Add(val1)
val1 = Nothing


'====================================================
'Bytevariable MB501
Dim val2 As New PLCTag
val2.LibNoDaveDataSource = TagDataSource.Flags
val2.LibNoDaveDataType = TagDataType.Byte
val2.ByteAddress = 501
val2.BitAddress = 0
val2.DatablockNumber = 200
val2.ArraySize = 1
TagList.Add(val2)
val2 = Nothing

'S-Bytevariable MB502
Dim val3 As New PLCTag
val3.LibNoDaveDataSource = TagDataSource.Flags
val3.LibNoDaveDataType = TagDataType.SByte
val3.ByteAddress = 502
val3.BitAddress = 0
TagList.Add(val3)
val3 = Nothing

'BCD-Bytevariable MB503
Dim val4 As New PLCTag
val4.LibNoDaveDataSource = TagDataSource.Flags
val4.LibNoDaveDataType = TagDataType.BCDByte
val4.ByteAddress = 503
val4.BitAddress = 0
TagList.Add(val4)
val4 = Nothing

End Sub

Die Routine zum lesen der Daten aus der SPS lautet „ListeLesen“ – sie soll die Variablenwerte aus der SPS laden und in ein DatagridView eintragen.
Sub ListeLesen()
If Con1_Verbunden = True Then
Dim Tags As New List(Of PLCTag)
'Liste der PLC-Variablen initialisieren
Call InitListe(Tags)
'====================================================
PLCCon1.ReadValues(Tags)
'====================================================
Dim N As Integer
Dim T(Tags.Count + 1) As String
For N = 0 To Tags.Count - 1
Me.dgv_Liste.Rows(N).Cells(0).Value = Trim(Str(N))
Me.dgv_Liste.Rows(N).Cells(1).Value = Tags(N).S7FormatAddress
Me.dgv_Liste.Rows(N).Cells(2).Value = Tags(N).LibNoDaveDataType.ToString
Me.dgv_Liste.Rows(N).Cells(3).Value = Tags(N).Value
Next
Tags = Nothing
Else
MsgBox("Erst Verbindung herstellen !", MsgBoxStyle.Information, "Hinweis !")
End If

End Sub

Das Ergebnis des zeigt im Anhang enthaltene Bild "Liste lesen".
Es ist zu erkennen, das die Variableneigenschaften richtig angezeigt, aber die Werte nicht aus der SPS geladen wurden.

Die Routine zum Schreiben der Variablen in die SPS lautet „ListeSchreiben“
Leider funktioniert auch diese Routine nicht.


Sub ListeSchreiben()
If Con1_Verbunden = True Then
MsgBox("Start Liste einlesen !")
Dim Tags As New List(Of PLCTag)
'Liste der PLC-Variablen initialisieren
Call InitListe(Tags)
MsgBox("Liste initialisiert !")
Dim N As Integer
Dim T(20) As String
Dim Value As String

For N = 0 To 3
N = Val(Me.dgv_Liste.Rows(N).Cells(0).Value)
Value = Me.dgv_Liste.Rows(N).Cells(3).Value
Tags(N).ParseControlValueFromString(Value)
Next
MsgBox("Parsen abgeschlossen !")
'====================================================
PLCCon1.WriteValues(Tags)
MsgBox("Schreiben beendet !")
Tags = Nothing
Else
MsgBox("Erst Verbindung herstellen !", MsgBoxStyle.Information, "Hinweis !")
End If
End Sub

Was mache ich hier falsch ?
Ich bin dankbar für Hilfe - hanjo


----------



## Jochen Kühner (17 März 2011)

*Quellcode...*

Mhmm...

Kannst mir mal deinen Quellcode zuschicken? Normal sollte das lesen gehen, so wie du es gemacht hast, mir ist beim Überfliegen jetzt kein Fehler aufgefallen.

Danke auch für das Prüfen der verschiedenen Formate, Ich werd mich gleich ans BugFixing machen...


----------



## Jochen Kühner (17 März 2011)

*Bugfixes...*

So hab mal ein paar Bugfixes gemacht...

- SByte -> geht nun.
- BCDWord -> geht, Frage mich nur ob man bei den BCD Typen ein vorzeichen unterstützen muss. Wenn, dann muss Ich das noch einbauen!
- BCDDWord -> geht nun.
- TIME -> Nur negative Werte gingen nicht, gehen nun!
- TIMEOFDAY -> Hab die Miliseconds Property statts der TotalMillisecondes verwendet... gefixt!
-----

-S5Time -> Geht bei mir, welchen Wert willst du den lesen oder schreiben? Hab da keinen Fehler gefunden
- DateTime -> Die Milisekunden werden mitgelesen, doch die ToString methode eines DateTime datentyps zeigt die MS nicht mit an !
- String: Ja man muss zuerst die Länge angeben! Sonst müsste Ich aber auch vor jedem schreiben Zwingend ein Lesen starten. Ist ja z.B. in Flexible auch so, das man die Länge angeben muss!

Nochwas:
So wie mirs scheint willst du dir ja sowas wie ne Variablentabelle bauen. Dann schau dir mal noch die Funktion SelectProjectPart.SelectTAG an, dann kannst du die PLCTags aus einem Step7 Projekt auswählen!


----------



## Jochen Kühner (17 März 2011)

*Nochwas...*

Über "SelectProjectPart.SelectVAT" kannst du dir auch die VATs eines Step7 Projektes importieren.


----------



## hanjo (17 März 2011)

*Anbei das VB-Projekt*

Hallo Jochen

1. Testprojekt
Ursprung des Testprojektes ist aus deiner Lib – VB.
Deshalb sind auch noch Überreste (Button 1 und Button 2 enthalten).
Ich habe das Testprojekt, das nur den Kommunikationstest enthält, im Anhang beigelegt.

2. BCD-Werte
BCD-Werte haben keine Vorzeichen :
WORD-BCD : 0000 … 9999
DWORD-BCD : 00000000 … 99999999

3. Hier nun das Ziel des Projektes :
Es ist schon richtig – ich möchte eine Art Protokoller gestalten.
Er unterscheidet sich von deinem etwas.

Beschreibung:
In der SPS werden Protokolldaten in einem Datenbaustein zusammengestellt.
Nach der Zusammenstellung werden die Daten von der SPS nicht mehr verändert.
Die SPS setzt ein Bit und zeigt dem PC an, in dem die Anwendung „Protokoller“ läuft, das die Daten zur Abholung bereitstehen.
Der „Protokoller“ prüft also zyklisch ob das Protokollbit gesetzt ist, holt die Daten wenn dies der Fall ist und löscht anschließend das Protokollbit.
In der SPS existiert ein Umlaufspeicher für Protokolldaten – immer wenn der „Protokoller“ Protokolldaten gelesen hat, stellt die SPS die nächsten zusammen.

Dieses Prinzip habe ich bereits mit dem alten INAT- Treiber realisiert.


----------



## hanjo (17 März 2011)

*Anbei das VB-Projekt*

Hallo Jochen
Im Anhang habe ich das Testprojekt verpackt.
Ursprung des Testprojektes ist aus deiner Lib – VB.
Deshalb sind auch noch Überreste (Button 1 und Button 2 enthalten).


BCD-Werte haben keine Vorzeichen :
WORD-BCD : 0000 … 9999
DWORD-BCD : 00000000 … 99999999

Hier nun das Ziel des Projektes :
Es ist schon richtig – ich möchte eine Art Protokoller gestalten.
Er unterscheidet sich von deinem etwas.
Beschreibung:
In der SPS werden Protokolldaten in einem Datenbaustein zusammengestellt.
Nach der Zusammenstellung werden die Daten von der SPS nicht mehr verändert.
Die SPS setzt ein Bit und zeigt dem PC an, in dem die Anwendung „Protokoller“ läuft, das die Daten zur Abholung bereitstehen.
Der „Protokoller“ prüft also zyklisch ob das Protokollbit gesetzt ist, holt die Daten wenn dies der Fall ist und löscht anschließend das Protokollbit.
In der SPS existiert ein Umlaufspeicher für Protokolldaten – immer wenn der „Protokoller“ Protokolldaten gelesen hat, stellt die SPS die nächsten zusammen.

Dieses Prinzip habe ich bereits mit dem alten INAT- Treiber realisiert.


----------



## Jochen Kühner (17 März 2011)

Werds morgen mal Testen, hab jetzt leider keine SPS mehr zur Verfügung!


----------



## Lars Weiß (17 März 2011)

Jochen Kühner schrieb:


> Hallo erst mal.
> 
> Das lesen funzt nicht da du die Funktion ReadValuesFromByteArray(aVar, Bytearray, 0) verwendest. Diese Funktion ist dazu da um den Tag mit Werten aus einem ByteArray zu befüllen das du z.B. per TCP direkt auf den PC schickst.
> 
> ...



Liest du die Variablen einzeln aus oder optimiert die Lib das Lesen der List ?


----------



## Jochen Kühner (17 März 2011)

Lars Weiß schrieb:


> Liest du die Variablen einzeln aus oder optimiert die Lib das Lesen der List ?



Noch nicht! Aber das wird noch implementiert!


----------



## PN/DP (18 März 2011)

hanjo schrieb:


> BCD-Werte haben keine Vorzeichen :
> WORD-BCD : 0000 … 9999
> DWORD-BCD : 00000000 … 99999999


Sind das spezielle BCD-Formate in Deinem Projekt?
In S7 haben BCD-Zahlen ein Vorzeichen:
16 Bit: -999 bis +999
32 Bit: -9.999.999 bis +9.999.999

Harald


----------



## PN/DP (18 März 2011)

S7: Beim Umwandeln einer BCD-Zahl in eine Ganzzahl wird nur das höchstwertige Bit als Vorzeichen ausgewertet, die anderen 3 Bits in der Vorzeichen-Tetrade werden ignoriert (dürfen also durchaus auch 0 sein).

Harald


----------



## Jochen Kühner (18 März 2011)

@hanjo:

Also bei mir hat dein Beispielprojekt an der CPU anstandslos funktioniert. Die MW werden gelesen! Wenns immer noch nicht geht, schick mal ne Wireshark Aufzeichnung.


----------



## Jochen Kühner (18 März 2011)

PN/DP schrieb:


> Sind das spezielle BCD-Formate in Deinem Projekt?
> In S7 haben BCD-Zahlen ein Vorzeichen:
> 16 Bit: -999 bis +999
> 32 Bit: -9.999.999 bis +9.999.999
> ...



Das werd Ich dann natürlich ändern. Ich hab die BCD Zahlen im Moment ohne Vorzeichen realisiert, wobei Ich die eh noch nie gebraucht habe!


----------



## hanjo (18 März 2011)

1. Danke für den Test meines Testprogrammes

Ich werde es am Montag nochmals ausprobieren.

2. BCD-Zahlen

Ich habe nur quer Beet alle Varianten deiner DLL erprobt.
Selber hab ich sie noch nicht benötigt - also lass es so wie es ist.


3. Und nun doch noch eine Frage

Wie due in meinem Testprogramm vieleicht bemerkt hast, habe ich den Aufruf und das Einlesen einer Symboldatei mittels deiner DLL bereits integriert.
Funktioniert wunderbar.
Nun meine Frage:
Die Rückgabe eines BlockTags ist mir auch gelungen.
Ist es möglich die Auflistung der in einem Datenbaustein (Block) enthaltenen Tags heranzukommen?
Bis jetzt ist es mir immer nur gelungen einen TAG des Blocks zu lesen.

Vielen Dank für Bemühungen hanjo


----------



## Jochen Kühner (18 März 2011)

hanjo schrieb:


> 1. Danke für den Test meines Testprogrammes
> 
> Ich werde es am Montag nochmals ausprobieren.


Jo schreib mir dann obs ging!



hanjo schrieb:


> 2. BCD-Zahlen
> 
> Ich habe nur quer Beet alle Varianten deiner DLL erprobt.
> Selber hab ich sie noch nicht benötigt - also lass es so wie es ist.


Zu spät, nun hab Ichs schon geändert! Und wenns drinn ist solls ja auch richtig sein!



hanjo schrieb:


> 3. Und nun doch noch eine Frage
> 
> Wie due in meinem Testprogramm vieleicht bemerkt hast, habe ich den Aufruf und das Einlesen einer Symboldatei mittels deiner DLL bereits integriert.
> Funktioniert wunderbar.
> ...



Ja das geht! Nutze Ich z.B. in ToolBoxForSiemensPLCs um Datenbausteinwerte Online anzuschauen.

Beispielcode:


```
S7DataBlock myBlock = woher auch immer...
List<S7DataRow> tmpLst = S7DataRow.GetChildrowsAsList(myBlock.Structure);
List<PLCTag> valueList = S7DataRow.GetLibnoDaveValues(askLst);
```
Hier wandelst du erstmal die Hirachische Struktur des DBs in eine flache Liste um (tmpLst) und dann Wird davon eine Liste von PLCTags erstellt (valueList )


----------



## hanjo (18 März 2011)

*Noch ne Frage*

Hallo Jochen

Dein Beispielcode ist sehr interessant:

Wie kann ich den S7DataBlock myBlock aus einem Offlineprojekt versorgen (laden) ?

Die zweite und dritte Zeile deines Codes ist eindeutig - in VB lauten sie wohl:

 Dim myBlock As New S7DataBlock()
 Dim tmpList As New List(Of S7DataRow)
 Dim valueList As New List(Of PLCTag)


        tmpList = S7DataRow.GetChildrowsAsList(myBlock.Structure)
valueList = S7DataRow.GetLibnoDaveValues(tmpList

Wie aber kann die "myBlock" Variable versorgen ?

z.B. myBlock=Projectfiles.SelectProjectPart.   - wie?


Dankbar für eine Antwort - hanjo


----------



## Jochen Kühner (18 März 2011)

In deinem Code kannst du dir das New sparen:

```
Dim myBlock As New S7DataBlock()
Dim tmpList As New List(Of S7DataRow)
Dim valueList As New List(Of PLCTag)


tmpList = S7DataRow.GetChildrowsAsList(myBlock.Structure)
valueList = S7DataRow.GetLibnoDaveValues(tmpList)
```

Da du später den variablen ja eine neue Instanz zuweist, sonst wird unötigerweise eine Instanz erzeugt!

Die Funktion Projectfiles.SelectProjectPart gibt es für einen datablock noch nicht (könnte Ich aber einbauen.). Du kannst aber mit Projectfiles.SelectProjectPart.SelectBlocksOfflineFolder eine Instanz von BlocksOfflineFolder bekommen aus der kannst du mit readPlcBlocksList() die enthaltet Bausteine auflisten, und mit GetBlock bekommst du dann auch den Block (wenn es ein S7-DB ist als S7DataBlock Instanz!)


----------



## Jochen Kühner (21 März 2011)

@hanjo:

Hat das mit dem Lesen und Schreiben nun funktioniert?


----------



## hanjo (22 März 2011)

*Lesen und Schreiben probiert*

*Hallo Jochen*

Ich habe das Lesen und Schreiben mit der Version 74916 probiert und deiner neuen umbenannten libnodave_jfkmod.dll.
Es funktioniert alles wie es soll - verstehe nicht warums beim ersten mal nicht geklappt hat.

Werde es demnächst auch immer wieder mit deiner neusten Version prüfen-
Z.B der Verrsion 74916.

Anmerkung : 
Auch so, eines ist mir aufgefallen, bei allen Versionen muss ich die 
Höhe der Forms
- PLCTagEditor
- SelectProjectPartForm
- ConnectionEditor 
vergrössern, damit sie ganz (in voller Höhe ) angezeigt werden.
Beispiel für die Orginal und die vergrösserte Darstellung (nur Höhe). siehe Anhang.

Ich arbeite mit Windows 7 32 Bit und Visual Studio 2010.

Bin begeistert von den Möglichkeiten der Verwendung orginaler Step7-Projekte - z.B. öffnen eines Projektes , auslesen der Symboldateien und ...

Grosses Lob für deine Arbeit - sehr gut.

hanjo


----------



## Jochen Kühner (22 März 2011)

hanjo schrieb:


> Anmerkung :
> Auch so, eines ist mir aufgefallen, bei allen Versionen muss ich die
> Höhe der Forms
> - PLCTagEditor
> ...



Kann Ich mir im Moment nicht erkläre, auf meinem PC und denen meiner Kollegen passt das Fenster! Hast du irgendwas an den Darstellungsoptionen von Windows umgestellt? 

Vielleicht hat sonst noch jemand das gleiche Problem?


----------



## hanjo (24 März 2011)

*Hallo Jochen*

*Lesetest - verschiedene Varianten*

Ich habe heute verschiedene Lesetests durchgeführt.
Unter „Lesetest“ verstehe ich dabei das Lesen von Variablen aus der SPS.
Die Lesetestergebnisse sind in der Exceldatei im Anhang dargestellt.
*Lesetest Variante 1*
Lesen eines ByteArrays (zusammenhängender Bereich)

Basis : DotNetSiemensPLCToolBoxLibrary
PLCCon1.ReadValue(aVar) - aVar ist eine Liste von PLCTags – „TagList As List(Of PLCTag)”
*Lesetest Variante 2*
Lesen einer zuvor zusammengestellten Variablenliste

Basis : DotNetSiemensPLCToolBoxLibrary
PLCCon1.ReadValue(aVar) - Var ist ein ByteArray – Einzelvariable

*Lesetest Variante 3*
Lesen eines Bytearrays mit bis zu 220 Bytes

Basis : LibNoDave
res = dc.readBytes(libnodave.daveFlags, 0, 500, M, buf)
M= Anzahl der gelesenen Bytes

*Lesetest Variante 4*
Lesen eines Bytearrays mit mehr als 220 Bytes

Basis : LibNoDave
res = dc.readManyBytes(libnodave.daveFlags, 0, 500, M, buf)
M= Anzahl der gelesenen Bytes

*Zusammenfassung und Frage*
Die Variante 1 sollte, meiner Meinung nach, in etwa die gleiche Funktion sein wie die in Variante 4.
Beide Varianten lesen ein zusammenhängendes ByteArray mit gleichem Leseergebnis :

Variante 1 : Verwendet „DotNetSiemensPLCToolBoxLibrary„
Variante 4 : Verwendet „LibNoDave“ in der „DotNetSiemensPLCToolBoxLibrary“

Die Lesezeit für 700-Bytes dauert 
für Variante 1 min. 499ms360µs686ns und 
für Variante 4 min. 18ms761µs135ns

Das ist ein erheblicher Unterschied.
Ich habe daraufhin mal in deiner „DotNetSiemensPLCToolBoxLibrary“


Ø unter „PLCConnection.cs“ 
Ø in der Funktion „public void ReadValue(PLCTag value)“
Ø die Zeile in der gelesen wird - auskommentiert
„int res = _dc.readManyBytes(Convert.ToInt32(value.LibNoDaveDataSource), value.DatablockNumber, value.ByteAddress, readSize, ref myBuff);

Dann wird zwar nicht mehr gelesen, - die Aufrufdauer liegt dann bei 2ms, d.h. der große Lesezeitunterschied liegt in dieser Funktion begründet.

Meine Frage :
Warum dauert das Lesen gegenüber dem Originalaufruf der LibNoDave so viel länger?
Ich würde die Variante 1 lieber verwenden, weil ich in diesem Fall deine Funktionen zur Konfiguration und zum Aufbau der Verbindung verwenden kann.
Ich habe übrigens auch erprobt das Bytearray „ref myBuff“ in einer extra Funktion direkt auszugeben – aber auch dieser Aufruf verkürzt die Lesedauer nicht.

Viele Grüsse hanjo


----------



## hanjo (24 März 2011)

*Hallo Jochen*

*Hab beim ersten mal vergessen den Anhang beizulegen*


*Lesetest - verschiedene Varianten*

Ich habe heute verschiedene Lesetests durchgeführt.
Unter „Lesetest“ verstehe ich dabei das Lesen von Variablen aus der SPS.
Die Lesetestergebnisse sind in der Exceldatei im Anhang dargestellt.
*Lesetest Variante 1*
Lesen eines ByteArrays (zusammenhängender Bereich)

Basis : DotNetSiemensPLCToolBoxLibrary
PLCCon1.ReadValue(aVar) - aVar ist eine Liste von PLCTags – „TagList As List(Of PLCTag)”
*Lesetest Variante 2*
Lesen einer zuvor zusammengestellten Variablenliste

Basis : DotNetSiemensPLCToolBoxLibrary
PLCCon1.ReadValue(aVar) - Var ist ein ByteArray – Einzelvariable

*Lesetest Variante 3*
Lesen eines Bytearrays mit bis zu 220 Bytes

Basis : LibNoDave
res = dc.readBytes(libnodave.daveFlags, 0, 500, M, buf)
M= Anzahl der gelesenen Bytes

*Lesetest Variante 4*
Lesen eines Bytearrays mit mehr als 220 Bytes

Basis : LibNoDave
res = dc.readManyBytes(libnodave.daveFlags, 0, 500, M, buf)
M= Anzahl der gelesenen Bytes

*Zusammenfassung und Frage*
Die Variante 1 sollte, meiner Meinung nach, in etwa die gleiche Funktion sein wie die in Variante 4.
Beide Varianten lesen ein zusammenhängendes ByteArray mit gleichem Leseergebnis :

Variante 1 : Verwendet „DotNetSiemensPLCToolBoxLibrary„
Variante 4 : Verwendet „LibNoDave“ in der „DotNetSiemensPLCToolBoxLibrary“

Die Lesezeit für 700-Bytes dauert 
für Variante 1 min. 499ms360µs686ns und 
für Variante 4 min. 18ms761µs135ns

Das ist ein erheblicher Unterschied.
Ich habe daraufhin mal in deiner „DotNetSiemensPLCToolBoxLibrary“


Ø unter „PLCConnection.cs“ 
Ø in der Funktion „public void ReadValue(PLCTag value)“
Ø die Zeile in der gelesen wird - auskommentiert
„int res = _dc.readManyBytes(Convert.ToInt32(value.LibNoDaveDataSource), value.DatablockNumber, value.ByteAddress, readSize, ref myBuff);

Dann wird zwar nicht mehr gelesen, - die Aufrufdauer liegt dann bei 2ms, d.h. der große Lesezeitunterschied liegt in dieser Funktion begründet.

Meine Frage :
Warum dauert das Lesen gegenüber dem Originalaufruf der LibNoDave so viel länger?
Ich würde die Variante 1 lieber verwenden, weil ich in diesem Fall deine Funktionen zur Konfiguration und zum Aufbau der Verbindung verwenden kann.
Ich habe übrigens auch erprobt das Bytearray „ref myBuff“ in einer extra Funktion direkt auszugeben – aber auch dieser Aufruf verkürzt die Lesedauer nicht.

Viele Grüsse hanjo


----------



## Jochen Kühner (24 März 2011)

*Mal sehn...*

Ich schau mirs morgen mal an. Als info vorab schon mal: der leseaufruf von mehreren zusammenhängenden plctags wird noch nicht optimiert! Dies ist aber in Arbeit, wird aber noch etwas dauern...


----------



## Jochen Kühner (24 März 2011)

Häng mal noch deinen Code an... (wenns geht!)


----------



## hanjo (25 März 2011)

*Na klar geht es - anbei der Code*

*Hallo Jochen*


Das Testprojekt habe ich im Anhang beigelegt.
Die entscheidenden Aufrufe befinden sich unter Tab-Reiter „Variablenliste“.

Variante 1 - Lesen eines zusammenhängenden Bytearrays mit deiner DLL

Variante 4 - Lesen eines zusammenhängenden Bytearrays mit LibNoDave 
Meiner Meinung wird in deiner DLL das Bytearray in gleicher Weise gelesen wie laut LibNoDave, eben mit ReadManyBytes. 
Ich glaube nicht, dass es mit der fehlenden Optimierung zu tun hat.
Viele Grüsse hanjo


----------



## hanjo (25 März 2011)

*Noch was als Ergänzung*

Hallo Jochen

im Anhang habe ich ergänzend die AWL-Quelle für den Test-DB3500 und eine VAT (Excel) zum schnelleren testen beigelegt.
Du kannst ja die DB-Nummer auch in eine andere umbenennen.
Bitte beachte, dass die DB-Nummer in meinem Code fix hinterlegt ist - die müsste dann auch geändert werden.
Die VAT kannst du aus der Exceldatei über die Zwischenablage in dein SPS-Projekt importieren.

Viele Grüsse hanjo


----------



## Jochen Kühner (25 März 2011)

Ein paar Infos....

Das ist schon mal falsch:

```
'Konfigurationsmenü Verbindung 1
Configuration.ShowConfiguration("SPS1", True)
PLCCon1.Configuration.ConnectionName = "SPS1"
```

der Code sollte so ausehen:

```
'Konfigurationsmenü Verbindung 1
        Configuration.ShowConfiguration("SPS1", True)
        PLCCon1 = New PLCConnection("SPS1")
```

Und bei mir dauert das lesen von 700 Bytes entweder über ReadTag oder über ReadManyBytes um die 110ms... also bei beiden gleich lang...
Sicher das dein readManyBytes auch funktioniert hat? den res value wertest du nämlich nicht aus!


----------



## Jochen Kühner (25 März 2011)

PS:

Habs auch noch so probiert:


```
Dim aa As New List(Of PLCTag)
            aa.Add(aVar)

            xTime2.Reset()
            xTime2.UhrStart()
            
            PLCCon1.ReadValues(aa) 'Neue Funktion Bytearray direkte Rückgabe 

            
            xTime2.UhrStop()
            txtDauer.Text = xTime2.DauerNanoSec
```

Dauert auch fast genau 110ms...

Hab dabei auch noch ein Bug bei ReadManyValues gefunden, wenn ein Tag nicht in die PDU gepasst hat! Fix dazu kommt...


----------



## hanjo (25 März 2011)

Hallo Jochen

die Instanz der Verbindung "SPS1" habe ich im Modul "mdl_Globals" bereits als Public PLCCon1 as New PLCConnection("SPS1") angelegt.

Ich dachte, dass ich dieser Instantz dann im 
'Konfigurationsmenü Verbindung 1
einfach nur zuordnen muss.

Das readManyBytes über die LibNoDave hat funkkktioniert-es ist aber korrekt, das Res habe ich nicht ausgewertet.

Mein Hardwareaufbau war:
S7-400
CPU417-4
CP443-1

Ich probier es am Montag noch mal.

Vielen Dank für deine Bemühungen.

Gruss hanjo


----------



## Jochen Kühner (25 März 2011)

hanjo schrieb:


> Hallo Jochen
> 
> die Instanz der Verbindung "SPS1" habe ich im Modul "mdl_Globals" bereits als Public PLCCon1 as New PLCConnection("SPS1") angelegt.



Das Problem ist, das New PLCConnection("SPS1") im Konstruktor aus der Registry liest. Ich könnte auch reinmachen das die Config vor dem Verbindungsaufbau nochmals gelesen wird, dann wird diese Zeile überflüssig:

```
PLCCon1 = New PLCConnection("SPS1")
```
aber den ConnectioNamen nochmals zuweisen wie hier:

```
PLCCon1.Configuration.ConnectionName = "SPS1"
```
ist auf jeden Fall nicht nötig!


----------



## hanjo (25 März 2011)

Danke für die Erklärung !

Ich werde es jetzt so ausführen wie von dir vorgeschlagen.

Gruss hanjo


----------



## Jochen Kühner (25 März 2011)

*So...*

Hab jetzt auch mal noch ne optimier Funktion bei ReadValues eingebaut, diese kombiniert verschiedene Tags wenn das Ende eines Tags nicht weiter als 4 Byte entfernt liegt! Oder auch überlappende Bytes werden kombiniert!


----------



## Forscher (18 April 2011)

Jochen Kühner schrieb:


> Hab jetzt auch mal noch ne optimier Funktion bei ReadValues eingebaut, diese kombiniert verschiedene Tags wenn das Ende eines Tags nicht weiter als 4 Byte entfernt liegt! Oder auch überlappende Bytes werden kombiniert!



Ja, so eine Optimierung hab ich auch schon mal realisiert. Aber das theoretische Optimum ist bei einer Lücke mit 16 Bytes. 

Jede Antwort hat einen Protokoll-Overhead von 4 Bytes. Aber auch der Request hat einen Overhead von 12 Bytes!. Mit jedem Paket das angefordert wird, gibt das einen Overhead von 4+12 = 16 Bytes. Es ist also effizienter, eine Lücke von 16Bytes mitzulesen, als das in zwei Aufrufen zu machen. 

Aus der praktischen Erfahrung ergab sich sogar, daß für die effektive Bandbreite das Optimum bei einer Lücke von 20(!) Bytes liegt. Das ergibt zwar wieder mehr Busverkehr, aber im Datendurchsatz (kB/sec) ist hier das Maximum zu messen. (Kann aber abhängig vom SPS-Typ sein). Vermutlich tut sich die SPS intern auch leichter, einen längeren Block am Stück zu kopieren, als zwei kleine.


----------



## Jochen Kühner (18 April 2011)

Forscher schrieb:


> Ja, so eine Optimierung hab ich auch schon mal realisiert. Aber das theoretische Optimum ist bei einer Lücke mit 16 Bytes.
> 
> Jede Antwort hat einen Protokoll-Overhead von 4 Bytes. Aber auch der Request hat einen Overhead von 12 Bytes!. Mit jedem Paket das angefordert wird, gibt das einen Overhead von 4+12 = 16 Bytes. Es ist also effizienter, eine Lücke von 16Bytes mitzulesen, als das in zwei Aufrufen zu machen.
> 
> Aus der praktischen Erfahrung ergab sich sogar, daß für die effektive Bandbreite das Optimum bei einer Lücke von 20(!) Bytes liegt. Das ergibt zwar wieder mehr Busverkehr, aber im Datendurchsatz (kB/sec) ist hier das Maximum zu messen. (Kann aber abhängig vom SPS-Typ sein). Vermutlich tut sich die SPS intern auch leichter, einen längeren Block am Stück zu kopieren, als zwei kleine.



Also das das mit den 16 Bytes stimmt bin kann Ich nicht glauben, da Ich in eine Anfrage bei einer PDU größe von 240 Bytes 17 Tags bekomme, wenn diese jedoch alle 16 Bytes auseinander liegen würden, und Ich alle zusammenfassen würde, müsste meine Antwort 16*17 als mindestens 272 Bytes groß sein, was nicht mehr in eine PDU passt....


----------



## Forscher (18 April 2011)

Hallo Jochen,

so wie du schreibst, hast du natürlich recht, in dem Fall kommt man auf eine maximale sinnvolle Lücke von 10 Bytes. Dann passen 17 Antworten in eine PDU.

Bei mir ist der Fall etwas anders gelagert. Hier werden ca. 10.000 Variablen gelesen. Diese sind bunt im Speicher verteilt und haben unterschiedlichste Länge und Abstände. Statistisch gesehen habe ich dann Lücken zwischen 0 und 20 Bytes, welches im Mittel 10 ist. Es muss natürlich schon bei der Anfrage sichergestellt sein, daß die Länge der Antwort nicht überschritten ist. Die Prüfung muss sowieso stattfinden, da auch einzelne Bereiche mit einer Länge von z.B. 100Bytes gelesen werden. 

Wenn auf diese Weise zwei nahe beieinander liegende Tags in einen Request gepackt werden, dann kann ich sogar mehr als 17 Tags in eine PDU packen. 

Das ganze funktioniert aber nur effektiv, wenn ich die Tags in einer übergeordneten Klasse entsprechend vorsortiere. 

Ein Rechenbeispiel:

Normalerweise bekomme ich in eine PDU (240-18)/12=18 Requests. In der Antwort braucht das 18*(4+data) =108 Bytes. Damit ist aber noch massig Reserve für weitere Daten. Wenn ich nun noch ein paar Tags finde, die mit einer Lücke von z.B. 20 Bytes mitgelesen werden können, dann kann ich mit der selben Anzahl Requests noch >=4 weitere Tags mitlesen.


Fazit: 
Im worst case, wenn die Lücken immer genau 20Bytes sind, mache ich natürlich Verlust. Im statistischen Mittel habe ich jedoch das Optimum, wenn ich Lücken bis zu 20 Bytes zulasse. Die 20 Bytes sind empirisch ermittelt für meinen Anwendungsfall das Optimum. Ich will nicht behaupten, daß das allgemeingültig ist.


----------



## Forscher (18 April 2011)

P.S. 
Der Algorithmus zum verteilen der Tags auf die PDUs muss natürlich so ausgelegt sein, daß nicht alle Requests mit großen Antwortvolumen (und Lücken) in ein PDU gepackt werden. Wenn schon ein großer Brocken in der Antwort liegt, kann man aber immer noch kleine dazupacken!


----------



## Jochen Kühner (18 April 2011)

*Jo*

Also mein Algorythmus sieht im Moment so aus das Ich die Tags nach Addresse sortiere und wenn der Abstand kleiner 6 ist die Tags zusammenfasse! Dies ist auf jeden Fall immer von Vorteil! 
Werd mal schauen wie Ich das ganze noch verbessern kann! Kann den jemand sagen was für Optimierungen Aglink abeim lesen alles vornimmt?


----------



## Thomas_v2.1 (18 April 2011)

Also ich würde auch in 3 Schritten optimieren:
1) Nach Adressen sortieren
2) Überlappende Speicherbereiche erkennen (wenn z.B. ein Bit aus einem schon gelesenen Wort gelesen werden soll)
3) Optimales packen der Daten je nach ausgehandelter PDU-Größe, sodass eine minimale Anzahl an Requests gestellt werden muss (Rucksackproblem)

Ich habe mir das Packen irgendwann mal beim Wonderware DA-Server angesehen, welcher auch bei einem Abstand von zwei Variablen > 10 Byte noch zusammenhängend liest. Evtl. ist der Zugriff SPS-intern wirklich schneller wenn ein großer Block gelesen wird. Das bekommt man aber nur durch Versuche heraus (wobei ich das garnicht machen würde, weil man davon ausgehen muss dass sich das je nach CPU-Typ und Firmwareversion wieder ändert).

Am unteren Ende der Anbindungstreiber steht ja der von WinCCflexible. Der packt überhaupt nichts und liest Variablen sogar mehrfach ein. Kein Wunder dass das so lahm ist.


----------



## Jochen Kühner (18 April 2011)

Thomas_v2.1 schrieb:


> Also ich würde auch in 3 Schritten optimieren:
> 1) Nach Adressen sortieren
> 2) Überlappende Speicherbereiche erkennen (wenn z.B. ein Bit aus einem schon gelesenen Wort gelesen werden soll)
> 3) Optimales packen der Daten je nach ausgehandelter PDU-Größe, sodass eine minimale Anzahl an Requests gestellt werden muss (Rucksackproblem)
> ...



1 und 2 sind schon drinn!

Und 3 ja auch aber nur mit 6 Bytes! Kann's ja mal auf 10 erweitern und sehn was besser ist!


----------



## Thomas_v2.1 (18 April 2011)

Jochen Kühner schrieb:


> Und 3 ja auch aber nur mit 6 Bytes! Kann's ja mal auf 10 erweitern und sehn was besser ist!


Was meinst du mit 6 Bytes?

Ich meinte folgendes (nicht mit realen Daten).
Ausgehandelte PDU sei 100 Bytes (brutto=netto der Einfachheit halber):
- Bereich a hat 90 Bytes
- Bereich b hat 30 Bytes
- Bereich c hat 70 Bytes
- Bereich d hat 10 Bytes

Hier wäre es eben sinnvoll 
Request 1: a, d
Request 2: b, c
in ein Telegramm zu packen.

Einfach der Reihenfolge nach dem Sortierungsschritt würde sich evtl.
Request 1: a 
Request 2: b, c
Request 3: d 
ergeben.


----------



## Jochen Kühner (18 April 2011)

Thomas_v2.1 schrieb:


> Was meinst du mit 6 Bytes?
> 
> Ich meinte folgendes (nicht mit realen Daten).
> Ausgehandelte PDU sei 100 Bytes (brutto=netto der Einfachheit halber):
> ...



Nein Ich hab nur beim lesen drinn, das wenn 2 Tags max 6 Bytes auseinander liegen, diese auf ein Tag gepackt werden.
An so eine Analyse wie du beschreibst hab Ich auch schon gedacht, hab's aber im Moment verworfen, da mir noch kein einfacher algorytmus dazu eingefallen ist! Aber kann ja noch kommen!

Und flexible packt nichts?


----------



## maccap (30 April 2011)

*Datenbankprotokoller*

Hallo,

ich hänge mich mal an diesen Thread dran, da ich keinen zum Datenbankprotokoller finde. Ggf. bitte zu passenden Thread verschieben...

Ich versuche per Datenbankprotokoller eine Verbindung per Iso on TCP auf eine s7-1200 zu realisieren und die Daten in eine Datenbank abzulegen.
Leider kommt immer der Fehler  " Der Index war außerhalb des Arraybereichs"

Informationen über das Aufrufen von JIT-Debuggen
anstelle dieses Dialogfelds finden Sie am Ende dieser Meldung.

************** Ausnahmetext **************
System.IndexOutOfRangeException: Der Index war außerhalb des Arraybereichs.
   bei ProtkollerDatenbank.CreateDatabase(ProtokollDaten myProtokollDaten) in E:\Daten\Step7-Projekte\StandartAM\Addons\DotNetDatenbankProtokoller\ProtkollerDatenbank.cs:Zeile 422.
   bei ProtkollerDatenbank.OnStart(String[] args) in E:\Daten\Step7-Projekte\StandartAM\Addons\DotNetDatenbankProtokoller\ProtkollerDatenbank.cs:Zeile 116.
   bei ProtkollerDatenbank.testStart() in E:\Daten\Step7-Projekte\StandartAM\Addons\DotNetDatenbankProtokoller\ProtkollerDatenbank.cs:Zeile 82.
   bei ProtokollerDatenbankNS.appSettings.button7_Click(Object sender, EventArgs e) in E:\Daten\Step7-Projekte\StandartAM\Addons\DotNetDatenbankProtokoller\appSettings.cs:Zeile 58.
   bei System.Windows.Forms.Control.OnClick(EventArgs e)
   bei System.Windows.Forms.Button.OnClick(EventArgs e)
   bei System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)
   bei System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
   bei System.Windows.Forms.Control.WndProc(Message& m)
   bei System.Windows.Forms.ButtonBase.WndProc(Message& m)
   bei System.Windows.Forms.Button.WndProc(Message& m)
   bei System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
   bei System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
   bei System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)

Leider fehlt mir VS 2003 und daher kann ich das Projekt nicht öffnen, um zu debuggen. Habe nur 2010 Express.

Wollte das ganze in ne Postgres DB schreiben. Dachte es könnte daran liegen, aber auch bei Ablage in einen Textfile taucht immer wieder dieser Fehler auf.

Gibt es eine Möglichkeit das Projekt auf 2010 zu konvertieren?

Was kann ich an den Einstellungen noch tun.

Habe meine aktuellen Einstellungen angehängt.

Vielen Dank.

Gruß Maccap


----------



## Jochen Kühner (30 April 2011)

maccap schrieb:


> Hallo,
> 
> ich hänge mich mal an diesen Thread dran, da ich keinen zum Datenbankprotokoller finde. Ggf. bitte zu passenden Thread verschieben...



Da es in diesen Thread wirklich nicht passt, hilft auch das anlegen eines neuen!

Ob 1200er Cpu funktioniert, kann Ich nicht sagen, Ich hab keine! 

Stell mal deine komplette Config hier rein, Ich schau mir sie dann am Montag an (die config findest du im programm verzeichnis!)


----------



## maccap (30 April 2011)

Ich habe mal in die Datei ringeguckt. Ich glaube hier liegt auch das Problem.
Wenn Du meinen Screenshot mit den Einstellungen und die Datei vergleichst, stehen dort total verschiedene Sachen drin. Ich frage mich nur wo die Settings dann abespeichert werden. Wenn ich nämlich das Programm neu starte und auf Settings gehe stehen auch meine Sachen wieder drin, obwohl an der ..protokoller.exe.config nichts geändert wird.

Habe alles in ne txt gepackt, da die config-endung als Anhang nicht zugelassen ist.

Gruß Maccap


----------



## Jochen Kühner (30 April 2011)

Nee, schau mal nach einer "ProtokollerDatenbank.settings" und häng diese an!


----------



## maccap (30 April 2011)

Oh sorry.

Habe jetzt das Projekt in C:\Protokoller entpackt, hatte es vorher auf dem Desktop liegen. Jetzt kommt der Fehler "Das Ereignisprotokoll ist voll"

Anbei meine Configdatei

Die Kommunikation zur S7-1200 funktioniert bei mir über Rack 0 Slot 1 und Iso over TCP auf Port 102.

Gruß Maccap


----------



## Jochen Kühner (30 April 2011)

*Dann...*

Dann leer mal das erignisprotokoll (Systemsteuerung/Verwaltung), schalten in meinem programm detailed logging ein (in den settings), drücke auf test, warte kurz, dann auf stop test, und schick mir einen auszug om ereignisprotokoll!

Die Config sieht gut aus, vorrausgesetzt du hast im db4 am anfang ein chararray mit 255 zeichen.

Das port=5433 in dem db connection string, hast du das reingeschrieben? Den werte ich bei postgres nämlich nicht aus, d.h. wenn du nicht den standart port hast gehts deswegen schonmal nicht (das kann ich aber einstellbar machen!)


----------



## maccap (30 April 2011)

Jetzt kommen wir der Sache näher.
Hier mein Fehler:
CLMP CSHARP-LibNoDave-MySQL-Protokoller: Fehler beim erzeugen des Physical Interface, d.h. falsche IP, falscher COM Port, fehlende S7 Treiber! . PLCCOnnectionID:0

Scheint an der S7-verbindung zu liegen.

Habe aber mit folgendem Einstellungen schon per libnodave erfolgreich auf die 1200er zugreifen können:

  fds.rfd = libnodave.openSocket(102, 192.168.0.30) 
            fds.wfd = fds.rfd 
            di = New libnodave.daveInterface(fds, "Mein Interface", 2, _
            libnodave.daveProtoISOTCP, libnodave.daveSpeed187k)
            di.setTimeout(1000000)
 res = di.initAdapter

            If res = 0 Then       
                dc = New libnodave.daveConnection(di, 2, 0, 1)
                res = dc.connectPLC()
            End If


Gruß maccap


----------



## Jochen Kühner (30 April 2011)

maccap schrieb:


> Jetzt kommen wir der Sache näher.
> Hier mein Fehler:
> CLMP CSHARP-LibNoDave-MySQL-Protokoller: Fehler beim erzeugen des Physical Interface, d.h. falsche IP, falscher COM Port, fehlende S7 Treiber! . PLCCOnnectionID:0
> 
> ...



Welche Libnodave hast du denn da verwendet? Die orginale oder meine angepasste? 

Versuch mal die libnodave welche beim protokoller dabei ist durch die mit der es funktioniert hat zu ersetzten (ist glaub noch ne alte version)


----------



## Jochen Kühner (30 April 2011)

Achso nochwas, wenn du den Source mit VS-Express nicht öffnen kannst, probiers doch mit SharpDevelop!


----------



## Jochen Kühner (30 April 2011)

maccap schrieb:


> Jetzt kommen wir der Sache näher.
> Hier mein Fehler:
> CLMP CSHARP-LibNoDave-MySQL-Protokoller: Fehler beim erzeugen des Physical Interface, d.h. falsche IP, falscher COM Port, fehlende S7 Treiber! . PLCCOnnectionID:0



Was mich noch wundert, wenn dieser Fehler kommt, liefert openSocket 0 zurück!


----------



## maccap (30 April 2011)

Vielen Dank erstmal an dieser Stelle für deine Hilfe...

So, habe jetzt das Projekt irgendwie in meine vs express 10 Version bekommen.
Habe den Daveconn angepasst und siehe da, mein Fehlerspeicher bleibt leer.

Nun möchte ich den Browser benutzen, um auf die DB zuzugreifen. Dann bekomme ich folgenden Fehler:

Die Assembly im gemischten Modus wurde während Version v2.0.50727 der Laufzeit erstellt und kann nicht während der 4.0-Laufzeit ohne zusätzliche Konfigurationsinformationen geladen werden.

System.IO.FileLoadException

Weißt Du, Wie ich  die 4.00er Version in das Projekt bekomme?

gruß maccap


----------



## Jochen Kühner (30 April 2011)

maccap schrieb:


> Vielen Dank erstmal an dieser Stelle für deine Hilfe...
> 
> So, habe jetzt das Projekt irgendwie in meine vs express 10 Version bekommen.
> Habe den Daveconn angepasst und siehe da, mein Fehlerspeicher bleibt leer.


Häää?????



maccap schrieb:


> Nun möchte ich den Browser benutzen, um auf die DB zuzugreifen. Dann bekomme ich folgenden Fehler:


Welchen Browser? Der bei mir Integrierte um die Daten anzuschauen? Den hab Ich bis jetzt nur mit SQLLite benutzt, bei den anderen Verbindungen geht der wahrscheinlich nicht!


----------



## maccap (30 April 2011)

Hier meine gänderten Zeilen:

 myDaveInterface = new libnodave.daveInterface(myPH, "ProtokollInterface", 2, libnodave.daveProtoISOTCP, libnodave.daveSpeed187k);           

myDaveConnection = new libnodave.daveConnection(myDaveInterface, 2, 0 , 1);

Ich habe keine Fehler mehr in der Ereinisanzeige, wenn ich den test button drücke.
Leider werden immer noch keine Daten geschrieben.

Zu deinem Datenbrowser:
Der funktioniert einwandfrei mit postgres. Wenn ich deine debugversion starte kann ich die DB öffnen und sehe die tabelle mit den angelegeten spalten.


----------



## Jochen Kühner (30 April 2011)

Ja schreibt er denn jetzt alle 2 sekunden was ins ereignisprotokoll (detailed logging muss true sein!).?

Warum es ging wenn du die 2 Zeilen änderst ist mir nicht klar...


----------



## maccap (30 April 2011)

irgendwo hängts noch. das sind die ereignisse, wenn ich auf test drücke:

CLMP CSHARP-LibNoDave-MySQL-Protokoller: Versuche Verbindungen aufzubauen (1 Stück)

Weitere Informationen über die Hilfe- und Supportdienste erhalten Sie unter http://go.microsoft.com/fwlink/events.asp.

CLMP CSHARP-LibNoDave-MySQL-Protokoller: Verbindung ID:1 ArtLCConnection wurde aufgebaut

Weitere Informationen über die Hilfe- und Supportdienste erhalten Sie unter http://go.microsoft.com/fwlink/events.asp.

CLMP CSHARP-LibNoDave-MySQL-Protokoller: wurde gestartet.

Weitere Informationen über die Hilfe- und Supportdienste erhalten Sie unter http://go.microsoft.com/fwlink/events.asp.


dann passiert gar nix....


----------



## maccap (30 April 2011)

Wer lesen kann ist klar im Vorteil....

das Intervall habe ich auf 2000 eingestellt.

Jetzt habe ich erst gesehen, dass das keine ms sondern sec sind.

Er schreibt!!!!

Danke Dir.


----------



## Jochen Kühner (30 April 2011)

*Intervall...*

Du hast ein Intervall von 2000 eingestellt, d.h. 2000 Sekunden!


----------



## maccap (30 April 2011)

wieso die verbindung mit den änderungen funzt, wissen wir immer noch nicht oder?


----------



## Jochen Kühner (30 April 2011)

*Haltepunkt...*

Setz doch mal einen Haltepunkt und schau wo er dann abbricht!


----------



## Jochen Kühner (30 April 2011)

maccap schrieb:


> wieso die verbindung mit den änderungen funzt, wissen wir immer noch nicht oder?



Also, ich habs Jetzt nochmals mit deiner Config debugt, und es wird bei mir dann im Endeffekt der gleiche Code aufgerufen wie durch deine Änderungen. Sollte daher auch ohne diese laufen!


----------



## maccap (30 April 2011)

Ja ich denke du hast Recht.

Habe mit der geänderten Version Probleme bekommen. Verbindung zur SPS war nicht mehr möglich, genau wie am Anfang. Nach Neustart des Rechners und Kaltstart der CPU läuft es wieder. 

Jetzt habe ich auch deinen Release ausprobiert und siehe da er läuft auch.

Kann ich wieder von vorne anfangen, um den Grund des Problems zu finden. Liegt anscheinend an der Schei.. S7-1200. 

Vielen Dank für Deinen Support.

Gruß Maccap


----------



## Jochen Kühner (1 Mai 2011)

Kann natürlich auch noch ein problem mit dem Verbindungsabbau im Protokoller sein, vielleicht hab Ich da ja noch einen Bug!


----------



## Sersch (28 Oktober 2011)

Hallo Jochen.

Hab mittlerweile ein tolles Tool mithilfe deiner Lib hingekriegt 

Frage zum "Datenbausteine auslesen" bzw. eine "Instanz auf einen Datenaustein erstellen": wie ich zu den Instanz-DB (Typ 'Instanzdatenbaustein zu FBxx') komme ist mit klar (.GetBlock). Aber WIE komme ich zu einem "normalen" DB (Typ 'Datenbaustein')?



> Die Funktion Projectfiles.SelectProjectPart gibt es für einen datablock noch nicht (könnte Ich aber einbauen.). Du kannst aber mit Projectfiles.SelectProjectPart.SelectBlocksOfflineFolder eine Instanz von BlocksOfflineFolder bekommen aus der kannst du mit readPlcBlocksList() die enthaltet Bausteine auflisten, und mit GetBlock bekommst du dann auch den Block (wenn es ein S7-DB ist als S7DataBlock Instanz!)


 
Mein Ziel ist, auch alle Items von diesem nicht-Instanz-DB zu durchsuchen...

Besten Dank, sersch


----------



## Sersch (7 November 2011)

Hallo zusammen.

Ich versuch nochmals, meine Frage genauer zu beschreiben:
Wie genau komme ich an die Struktur eines Datenbausteins (Typ=Datenbaustein)? Also ich möchte die *"flache" Struktur eines bestimmten DB's durchsuchen*; suche nach einem bestimmten Eintrag und möchte diesen dann als PLCTag weiterverwenden. Wie komme ich an den DB Inhalt?
Kannst mir bitte jemand helfen?

Besten Dank, sersch


----------



## Sersch (7 November 2011)

*DB Struktur auslesen (Code Bsp)*

Hier noch das Code-Bsp, welches mir Jochen mal gepostet hat:
=> funktioniert für Instanz-DB, leider aber nicht für "normale" DBs (Typ Datenbaustein).


```
Dim searchValue As String
        Dim db As String

        Dim tag As PLCTag
        Dim prj As Step7ProjectV5
        Dim fld As Projectfolders.Step7V5.BlocksOfflineFolder
        Dim blk As S7DataBlock

        searchValue = "SymbolDB_1000.Modul1.Temp4.Value"
        db = searchValue.Split(".")(0)
        searchValue = searchValue.Substring(db.Length + 1)
        prj = New Step7ProjectV5("C:\\Offenau_.s7p", False)

        
        fld = prj.BlocksOfflineFolders(1)

        For Each projectBlockInfo As S7ProjectBlockInfo In fld.readPlcBlocksList()
            If Not projectBlockInfo.SymbolTabelEntry Is Nothing And projectBlockInfo.SymbolTabelEntry.Symbol = db Then
                 blk = fld.GetBlock(projectBlockInfo)
```
'Hier wird bei einem Datenbaustein (nicht-Instanz-DB) immer eine Exception ausgegeben ?????
'die GetBlock-Funktion scheint hier wohl ein Problem zu haben.


```
End If
        Next

        If Not blk Is Nothing Then
            For Each s7DataRow As S7DataRow In s7DataRow.GetChildrowsAsList(blk.GetArrayExpandedStructure())
                If s7DataRow.StructuredName = searchValue Then
                    tag = s7DataRow.PlcTag
                End If
            Next
        End If
```

Wie kann ich den DB auslesen????????


----------



## Sersch (5 Dezember 2011)

*Fehler beim DB auslesen in DLL behoben *

Hallo zusammen.
Zur Info:
Jochen hat den Fehler in der Funktion fld.GetBlock(projectBlockInfo) behoben - funktioniert mit der neuesten Release von "DotNetSiemensPLCToolBoxLibrary" einwandfrei.
Merci, Gruss serge


----------

