# Libnodave getXXXfrom()



## Olli0285 (1 Juni 2010)

Hallo,

ich hab Mal wieder ein Problem mit Libnodave.

Ich wollte die getS32from(buf) benutzen, um einen DINT aus einem DB zu lesen, jedoch ist die Funktion im Wrapper nicht implementiert.

Mein Aufruf:
Private Declare Function daveGetS32from Lib "libnodave.dll" (ByRef buffer as Byte) as Integer

Variable= daveGetS32from(buf)

Fehler:
die funktion konnte in der dll nicht gefunden werden.

Vielleicht ist der Aufruf falsch.

Wäre schön wenn jemand etwas weiß!

VB.net
Libnodave 0.8.4.5

MfG

Olli


----------



## Jochen Kühner (1 Juni 2010)

*So..*

ich hab in meiner LibNoDave Connection Library eine erweiterte version des Wrappers mit mehr Funktionen....

siehe hier: http://www.sps-forum.de/showthread.php?t=36363

Kannst aber auch gleich die Connection Library verwenden...


----------



## Olli0285 (2 Juni 2010)

Hallo Jochen,

wie alt ist denn der Wrapper? ich hab letzte Woche deine aktuelleste Version runtergeladen! Ich weiß nur nicht wie man die fehlenden funktion von Libnodave in das VB Projekt implementiert. 
Ich lese in einem Sub vier Buffer Arrays aus und ich weiß nicht ob dann die Zeigerfunktion mit getS32at(buf) das richtige array benutzt. Ich poste gerne Mal den ganzen Code wenn es hilft. Mit der Bitabfrage funktioniert alles. 

Das Problem ist das ich aus den Bytes keinen 4Byte langen Integer kriege. Das Auslesen in den Buffer funktioniert problemlos

Ich denke es hängt am:

Privat Function........

Ich weiß es aber nicht!

MfG

Olli


----------



## Jochen Kühner (2 Juni 2010)

Olli0285 schrieb:


> Hallo Jochen,
> 
> wie alt ist denn der Wrapper? ich hab letzte Woche deine aktuelleste Version runtergeladen! Ich weiß nur nicht wie man die fehlenden funktion von Libnodave in das VB Projekt implementiert.
> Ich lese in einem Sub vier Buffer Arrays aus und ich weiß nicht ob dann die Zeigerfunktion mit getS32at(buf) das richtige array benutzt. Ich poste gerne Mal den ganzen Code wenn es hilft. Mit der Bitabfrage funktioniert alles.
> ...



JO poste mal Code....

Aber wie gesagt mit meiner Connection Lib kannst du mehrer Variablen einfach in ein Array Packen und dann einfach alle auf einmal lesen lassen.

Bsp:


```
private List<LibNoDaveValue> myValues = new List<LibNoDaveValue>();

myValues.Add(new LibNoDaveValue
                                   {
                                       LibNoDaveDataSource = LibNoDaveDataSource.Datablock,
                                       ByteAddress = 10 ,
                                       BitAddress = 0,
                                       DatablockNumber = 1,
                                       ArraySize = 0,
                                       LibNoDaveDataType = LibNoDaveDataType.Dword
                                   });
myValues = myConn.ReadValues(myValues);
```

Und schon sind alle Werte in der myValues Liste gelesen (hier nur db1.dbd10)


----------



## Olli0285 (2 Juni 2010)

Mein Code:

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

        Dim bufi(2) As Byte 'buffer inputs
        Dim bufo(0) As Byte 'buffer outputs
        Dim buff(0) As Byte  'buffer merker^^^^
        Dim bufdb(21) As Byte  'buffer DB
        Dim a123 As Integer

        dc.readBytes(daveInputs, 0, 0, 3, bufi) 'Eingänge laden
        dc.readBytes(daveOutputs, 0, 0, 1, bufo) 'Ausgänge laden
        dc.readBytes(daveFlags, 0, 0, 1, buff)  'Merker laden
        dc.readBytes(daveDB, 10, 0, 21, bufdb) 'Datenbaustein laden

        If bufi(0) And 64 Then     'E0.6
            PStanzeOben.Location = New Point(446, 259)
        Else : PStanzeOben.Location = New Point(446, 274)
        End If
        If bufi(0) And 128 Then         'E0.7
            PKlemmehi.Location = New Point(PBoxVorschub.Location.X, PKlemmehi.Location.Y)
            PBoxVorschub.Location = New Point(225, 291)
        ElseIf bufi(1) And 1 Then     'E1.0
            PKlemmehi.Location = New Point(PBoxVorschub.Location.X, PKlemmehi.Location.Y)
            PBoxVorschub.Location = New Point(158, 291)
        End If
        If bufi(1) And 2 Then 'E1.1
            PBand1.Visible = True
            PBand2.Visible = True
        Else
            PBand1.Visible = False
            PBand2.Visible = False
        End If
        If bufi(1) And 4 Then     'E1.2
            LblSiKe.Visible = False
        Else
            LblSiKe.Visible = True
        End If
        If bufi(2) And 16 Then     'E2.4 Autobetrieb
            LblGruSte.ForeColor = Color.LightGray
            LblAuto.BackColor = Color.Lime
            LblEinr.BackColor = Color.Gray
            LblAutoStart.ForeColor = Color.Black
            LblEinzel.ForeColor = Color.LightGray
            LblAutoStop.ForeColor = Color.Black
        ElseIf bufi(2) And 32 Then   'E2.5 Einrichtbetrieb
            LblAuto.BackColor = Color.Gray
            LblEinr.BackColor = Color.Lime
            LblEinzel.ForeColor = Color.Black
            LblAutoStart.ForeColor = Color.LightGray
            LblAutoStop.ForeColor = Color.LightGray
            LblGruSte.ForeColor = Color.Black

        Else      'Drehschalter Mittelstellung
            LblGruSte.ForeColor = Color.LightGray
            LblAuto.BackColor = Color.Gray
            LblEinr.BackColor = Color.Gray
            LblEinzel.ForeColor = Color.LightGray
            LblAutoStart.ForeColor = Color.LightGray
            LblAutoStop.ForeColor = Color.LightGray
        End If
        If bufo(0) And 4 Then
            LblMotStart.ForeColor = Color.LightGray
            LblMotStop.ForeColor = Color.Black
        Else
            LblMotStart.ForeColor = Color.Black
            LblMotStop.ForeColor = Color.LightGray
        End If
        If bufo(0) And 8 Then
            PBoxWickel.Visible = True
        Else
            PBoxWickel.Visible = False
        End If
        If bufo(0) And 32 Then
            PKlemmeVo.Location = New Point(372, 267)
        Else
            PKlemmeVo.Location = New Point(372, 259)
        End If
        If bufo(0) And 64 Then
            PKlemmehi.Location = New Point(PBoxVorschub.Location.X, 267)
        Else
            PKlemmehi.Location = New Point(PBoxVorschub.Location.X, 259)
        End If
        If buff(0) And 1 Then           'M0.0 Länge ein\aus
            CheckBoxLaenge.Checked = True
        Else
            CheckBoxLaenge.Checked = False
        End If
        If buff(0) And 2 Then           'M0.1 Länge ein\aus
            CheckBoxLaenge.Checked = True
        Else
            CheckBoxLaenge.Checked = False
        End If


    End Sub

Bis hierhin funktioniert alles ich ahbe aber in der bufDB() noch verschiedene Werte die ich auslesen möchte.


DB
0 S5t
2 DINT
6DINT
10INT
12INT
14 S5T
16 INT

Für diesen zweck bräuchte ich die gets16from bzw. die gets32from Funktion.

MfG

Olli


----------



## Jochen Kühner (2 Juni 2010)

Also bei mir ist die Funktion public static int getS32from(byte[] b, int pos) in meiner libnodave.net definiert!


----------



## Zottel (2 Juni 2010)

Jochen Kühner schrieb:


> Also bei mir ist die Funktion public static int getS32from(byte[] b, int pos) in meiner libnodave.net definiert!


Die Funktionen getXXfrom() sind aus folgendem Grund NICHT in den Interfaces für .NET, VB(A), PERL usw. enthalten:
Diese Sprachen kennen keine Zeiger im Sinne von C und Pascal (Zeiger ist eine Adresse im Speicher, ab dieser Adresse aufwärts existiert ein prinzipiell unbeschränkt langer, fortlaufender und byteweise adressierbarer Speicher, das Hochzählen der Adresse erfolgt in gleicher Weise in C und der Zielsprache).
getXXfrom() setzt voraus, daß mittels readDaveBytes(...,buffer) ein Zeiger auf einen Puffer übergeben wurde, von dem später gelesen werden kann. Auch das setzt schon die Existenz von Zeigern voraus.

Es mag z.Z. funktionieren, kann aber auch in der nächsten Variante von .NET in die Hose gehen.

Die .NET-Sprachen wurden mit dem Ziel entwickelt, der Laufzeitumgebung möglichst viel Kontrolle über das Speichermanagement zu geben.

Wenn man unbedingt mit Byte-Arrays in .NET arbeiten möchte, kann dieses in sauberer Art so erreicht werden:
1. benutze daveReadBytes ohne Puffer, d.h. mit null als letztem Parameter.
2. lies die Bytes mit daveGetBytes byteweise aus und lege sie im Ziel-Array ab.
3. Wiederhole diesen Vorgang, anstatt daveReadManyBytes aus der DLL zu benutzen.
4. Auf dieses Array können nun .NET-Varianten von getXXfrom() angewandt werden, die libnodave allerdings nicht mitbringt.


----------



## Jochen Kühner (2 Juni 2010)

Zottel schrieb:


> Die Funktionen getXXfrom() sind aus folgendem Grund NICHT in den Interfaces für .NET, VB(A), PERL usw. enthalten:
> Diese Sprachen kennen keine Zeiger im Sinne von C und Pascal (Zeiger ist eine Adresse im Speicher, ab dieser Adresse aufwärts existiert ein prinzipiell unbeschränkt langer, fortlaufender und byteweise adressierbarer Speicher, das Hochzählen der Adresse erfolgt in gleicher Weise in C und der Zielsprache).
> getXXfrom() setzt voraus, daß mittels readDaveBytes(...,buffer) ein Zeiger auf einen Puffer übergeben wurde, von dem später gelesen werden kann. Auch das setzt schon die Existenz von Zeigern voraus.
> 
> ...



Aber die getS32from ist doch in der libnodave.net enthalten (nicht als dll deklaration sondern als .net funktion). Und wenn er noch meine neueere libnodave.net verwendet, dann sind sogar noch ein paar mehr drin!


----------



## Earny (3 Juni 2010)

hallo,

dass die Funktion in der dll nicht gefunden wird, ist seltsam.

Bei der Deklaration der daveGetS32from-Funktion ist die Groß- und Kleinschreibung zu beachten. Schreibst Du daveGets16from, kommt eine Fehlermeldung "Einstiegspunkt in dll nicht gefunden...".

Du kannst auch mal den Versuch machen, die libnodave.dll ins System32 von Windows und außerdem, wenn Du in der Testumgebung von VB.Net arbeitest, in Bin/Debug des aktuellen Projekts zu legen. Ich weiß nicht, wo die libnodave.dll überall automatisch gesucht wird.

Gruß
Earny


----------



## Red-Sh4nks (4 Juni 2010)

> ich hab Mal wieder ein Problem mit Libnodave.
> 
> Ich wollte die getS32from(buf) benutzen, um einen DINT aus einem DB zu lesen, jedoch ist die Funktion im Wrapper nicht implementiert.
> 
> ...




DINT ist doch Double Int.
Int ist 32 Bit lang
DINT wäre dann 64 Bit lang.

Falls das bis hier nicht stimmt, ignorier bitte folgendes:

Du kannst das Ergebnis doch auch aus dem Puffer lesen
und ihn den gewünschten Datentyp konvertieren.

angenommen:

dc.davereadbytes(libnodave.davedb, 1, 0, 4, Puffer)
Puffer muss halt ein Array von der Mindestgröße 4 sein.

dannach:
convert.toint64(Puffer[0])

und schon hast du den Inhalt des Datenblocks 1 an der Stelle
0 gelesen und in den Datentyp DoubleInt konvertiert.

GetS32 ist daher überflüssig. Ich verwende es bei meinem Programm nicht.
Ich konvertiere das gelesene direkt in aus dem Lesepuffer in den gewünschten Datentyp ;-)

lg Marco*


----------



## Jochen Kühner (4 Juni 2010)

Red-Sh4nks schrieb:


> DINT ist doch Double Int.
> Int ist 32 Bit lang
> DINT wäre dann 64 Bit lang.
> 
> ...



in s7 ist ein dint 32 bit und ein normaler int 16 bit (die größe eines int's ist nicht vorgeschrieben, das ist architektur und programmiersprachen abbhänig!)

und was bringt dein convert?? da habe ich ein byte in ein int64 verwandelt! aber wenn er doch einen dint von der sps lesen will muss er ja 4 bytes gemeinsam umtauschen!


----------



## Jochen Kühner (4 Juni 2010)

Jochen Kühner schrieb:


> in s7 ist ein dint 32 bit und ein normaler int 16 bit (die größe eines int's ist nicht vorgeschrieben, das ist architektur und programmiersprachen abbhänig!)
> 
> und was bringt dein convert?? da habe ich ein byte in ein int64 verwandelt! aber wenn er doch einen dint von der sps lesen will muss er ja 4 bytes gemeinsam umtauschen!



und da libnodave ja auch unter mono auf einer anderen plattform laufen könnte musser beim umtauschen auch noch die bytereihenfolge (Endianes) beachten!


----------



## Red-Sh4nks (5 Juni 2010)

> aber wenn er doch einen dint von der sps lesen will muss er ja 4 bytes gemeinsam umtauschen!



hmmm... Hast recht. Aber dass kann ja nicht so schwer sein.


----------



## Jochen Kühner (6 Juni 2010)

Red-Sh4nks schrieb:


> hmmm... Hast recht. Aber dass kann ja nicht so schwer sein.




Nei ist ja auch nicht, deswegen gibt es die getS32From usw...


----------



## bool (7 Juni 2010)

Hallo habe das Problem grade in der anderen Richtung (schreiben, statt lesen) bei meinem VB.NET Proggi. Die die Funktionen libnodave.putU32() und libnodave.putS32() verursachen beim Ausführen eine Speicherbereichsverletzung "Der Index war außerhalb des Arraybereichs.". Ist dies hier wie von Zottel argumentiert in der Pointer Problematik von .NET begründet oder hat dies eine andere Ursache?
Hab das Problem nun folgendermassen gelöst, doch wollte ich verstehen weshalb es zu diesem Fehler kommt.

Problemcode:
Public testbuffer(220) AsByte
...
libnodave.putU32at(testbuffer, 0, intValue)
...

So gehts nun:
Case"DWord"
tempBuffer = BitConverter.GetBytes(intValue)
Buffer(0) = tempBuffer(3)
Buffer(1) = tempBuffer(2)
Buffer(2) = tempBuffer(1)
Buffer(3) = tempBuffer(0)
'libnodave.putU32at(testbuffer, 0, intValue)
res = dc.writeBytes(nArea, nDBnr, nByteAdr, nDataLength, Buffer)

Zusatzfrage: gibt es eigentlich auch eine Funktion libnodave.putU8() oder s.ä. oder wurde darauf verzichtet, da es sich nur um ein Byte handelt und sich die Byteausrichtung der CPU etc. hier nicht drauf auswirkt, bzw der Datentyp "Byte" ohnehin vozeichenlos ist?

Gruss,

bool


----------



## Jochen Kühner (7 Juni 2010)

bool schrieb:


> Hallo habe das Problem grade in der anderen Richtung (schreiben, statt lesen) bei meinem VB.NET Proggi. Die die Funktionen libnodave.putU32() und libnodave.putS32() verursachen beim Ausführen eine Speicherbereichsverletzung "Der Index war außerhalb des Arraybereichs.". Ist dies hier wie von Zottel argumentiert in der Pointer Problematik von .NET begründet oder hat dies eine andere Ursache?
> Hab das Problem nun folgendermassen gelöst, doch wollte ich verstehen weshalb es zu diesem Fehler kommt.
> 
> Problemcode:
> ...



Die putU32 at ist doch in der libnodave.net.dll fast genau so implementiert! Ich denke die mit nur einem Bytes gibt es nicht, da man ein byte einfach direkt in dem array zuweisen kann, bei den anderen funktionen muss halt wieder die endianess beachtet werden!


----------



## bool (7 Juni 2010)

Jochen Kühner schrieb:


> Die putU32 at ist doch in der libnodave.net.dll fast genau so implementiert!


 
... und doch gibt es die Speicherverletzung ...


Habe grad mal einen Blick in den Sourcecode der libnodave.net.dll gewagt und siehe da ...die Betonung liegt hier auf "fast":

public static void putU32at(byte[] b, int pos, int value)
{
byte[] bytes = BitConverter.GetBytes(Convert.ToUInt32(value));
if (BitConverter.IsLittleEndian)
{
b[pos + 3] = bytes[0];
b[pos + 2] = bytes[1];
b[pos + 1] = bytes[2];
b[pos] = *bytes[4]*;
}
else
Array.Copy(bytes, 0, b, pos, 4);
}

Ich vermute das "bytes[4]" musste "bytes[3]" heissen oder liege ich hier falsch?

Das selbe giltet übrigens auch für die Funktion "putS32at".

Gruss,

bool


----------



## bool (7 Juni 2010)

bool schrieb:


> Ich vermute das "bytes[4]" musste "bytes[3]" heissen oder liege ich hier falsch?
> 
> Das selbe giltet übrigens auch für die Funktion "putS32at".


 
scheint wohl tatsächlich "bytes[3]" heissen zu müssen. Habs grad in der cs geändert und neu compiliert, jetzt gehts auch ohne Speicherverletzung 

Gruss,

bool


----------



## bool (7 Juni 2010)

Habe da noch ein weiteres Problem festgestellt.

Wenn die Fuktion "putS16at" aufgerufen wird und ein Wert >32767 übergeben wird, gibt es ein exeption error, da angeblich durch "0" geteilt wird ebenso bei Verwendng eine negativen Zahl in Verbindung mit der Funktion "putU16at". 

GGf. sollten die Funktionen soweit "gehärtet" werden, dass die exeptions vermieden werden können. Vielleicht würde es hier dann Sinn machen wenn über einen Rückgabewert ein Fehlercode (z.B. "-1" oder FALSE) übergeben wird.

Die Frage wäre evtl. auch, ob die Konvertierung in INT16 bzw UINT16 vorab in den Funktionen nötig ist. Es werden ohnehin Funktionsintern nur die entsprechenden Bytes kopiert.

Gruss,

bool


----------



## Jochen Kühner (7 Juni 2010)

bool schrieb:


> Habe da noch ein weiteres Problem festgestellt.
> 
> Wenn die Fuktion "putS16at" aufgerufen wird und ein Wert >32767 übergeben wird, gibt es ein exeption error, da angeblich durch "0" geteilt wird ebenso bei Verwendng eine negativen Zahl in Verbindung mit der Funktion "putU16at".
> 
> ...



Hab das nun auch geändert, und die 16 Bit Funktionen so angepasst das sie einen short oder ushort zurückgeben oder erwarten. Ich denke, den Funktionen sollte auch nur der Datentyp übergeben werden, den Sie handeln können!


----------



## bool (7 Juni 2010)

Jochen Kühner schrieb:


> Ich denke, den Funktionen sollte auch nur der Datentyp übergeben werden, den Sie handeln können!


 
... stimme ich zu.


----------



## Olli0285 (16 Juni 2010)

*Fehler gefunden!*

Hallo,

hab meinen Fehler gefunden!

Der Fehler lag hier:

Private Declare Function daveGetS32from Lib "libnodave.dll" (ByRef buffer As Byte) As Integer

Beim Deklarieren der Funktion muß die Groß/Kleinschreibung beachtet werden.

Ich hatte alles klein geschrieben, weil es sonst keinen unterschied macht.

Danke für eure Mühe!

MfG

Olli


----------

