Wie am besten aus fertigem Beispiel, das in C geschrieben wurde, eine dll schreiben

  • C

Es gibt 37 Antworten in diesem Thema. Der letzte Beitrag () ist von chris_2091.

    Wenn FreespaceDeviceId als int typedefd ist gehts sogar noch einfacher.

    VB.NET-Quellcode

    1. <DllImport("libfreespace.dll",CallingConvention=...)>
    2. Public Shared Function freespace_getDeviceList(ByVal FreespaceDeviceId() As Int32, ByVal listSize As Int32, ByRef listSizeOut As Int32) As Int32
    3. End Function
    4. Private numIds As Integer
    5. Dim pList() As Int32 = new Int32(0){}//daran werd ich mich nie gewöhnen
    6. rc = Sensor.freespace_getDeviceList(pList, pList.Length, numIds)

    numIds wird nie größer werden als pList.Length. D.h. bei einem Element wird numIds entweder 0 sein(kein Device gefunden) oder 1.
    Man kann sich das ganze sogar noch etwas einfacher machen, für den Fall, dass man nur ein Element holen will:

    VB.NET-Quellcode

    1. <DllImport("libfreespace.dll",CallingConvention=...)>
    2. Public Shared Function freespace_getDeviceList(ByRef FreespaceDeviceId As Int32, ByVal listSize As Int32, ByRef listSizeOut As Int32) As Int32
    3. End Function

    dabei rufst du es immer mit einer festen listSize von 1 auf und gibst die variable, die du zur deviceID gesetzt haben will als ersten Parameter, dann brauchst du kein Array dazwischen.
    Ich wollte auch mal ne total überflüssige Signatur:
    ---Leer---
    Danke für den Hinweis @jvbsl !! Ich habe das jetzt auch so umgesetzt.

    Als CallingConvention habe ich jetzt folgendes

    VB.NET-Quellcode

    1. <DllImport("libfreespace.dll", CallingConvention:=CallingConvention.Cdecl)>
    2. Public Shared Function freespace_getDeviceList(ByRef FreespaceDeviceId As Int32, ByVal listSize As Int32, ByRef listSizeOut As Int32) As Int32
    3. End Function

    Die Funktion gibt immer null raus egal ob ich den Sensor angeschlossen habe oder nicht, lustigerweise scheint allerdings die ID richtig zu sein. Da ich als weitere Funktion

    VB.NET-Quellcode

    1. <DllImport("libfreespace.dll", CallingConvention:=CallingConvention.Cdecl)>
    2. Public Shared Function freespace_openDevice(ByVal FreespaceDeviceId As Int32) As Int32
    3. End Function
    benutze und sie gibt richtig aus, ob der Sensor angeschlossen ist oder nicht.

    Ansonsten funzt alles!! (soweit ich es austesten konnte) Man muss bei Funktionen die nichts zurückgeben das ganze als

    VB.NET-Quellcode

    1. <DllImport("libfreespace.dll", CallingConvention:=CallingConvention.Cdecl)>
    2. Public Shared Sub freespace_exit()
    3. End Sub
    definieren und nicht als Function.

    Eine Frage habe ich allerdings noch, und zwar bin ich jetzt dabei Nachrichten an den Sensor zu schicken. Dazu braucht man die Struktur freespace_message, die wie folgt definiert ist:
    freespace_message
    int messageType
    uint8_t ver
    uint8_t len
    uint8_t dest
    uint8_t src
    union { struct freespace_PairingMessage pairingMessage struct freespace_ProductIDRequest productIDRequest struct freespace_LEDSetRequest lEDSetRequest struct freespace_LinkQualityRequest linkQualityRequest struct freespace_AlwaysOnRequest alwaysOnRequest struct freespace_FrequencyFixRequest frequencyFixRequest struct freespace_SoftwareResetMessage softwareResetMessage struct freespace_DongleRFDisableMessage dongleRFDisableMessage ...nie endende Liste ;) };

    Braucht man wirklich alle!! Strukturen definieren (Bräuchte wahrscheinlich nur 5) ? Oder nur die man braucht und wie definiert man das ?
    Habe bisher nur

    VB.NET-Quellcode

    1. Public Structure FreespaceMessage ' aus der Doku
    2. Public messageType As Int32 ' int
    3. Public ver As Short 'uint16_t
    4. Public len As Short 'uint16_t
    5. Public dest As Short 'uint16_t
    6. Public src As Short 'uint16_t
    7. End Structure


    Nachtrag:
    Wie definiert man ein Array von Bytes?
    uint8_t meData [44]

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „chris_2091“ ()

    Kurze Antwort: Ein Union definierst du per StructLayout mit LayoutKind = Explicit unter Angabe der Offsets. Du brauchst nur die wirklich verwendeten Strukturen zu deklarieren.
    Das Array Definierst du mit MarshalAs und UnmanagedType = LPArray oder ByValArray mit Parameter SizeConst = 44.

    Achtung: Bei mir sind die Member von freespace_message uint8_t, nicht uint16_t - bitte kontrollieren. Außerdem: uint8_t ist Byte, int8_t ist SByte, uint16_t ist UShort, int16_t ist Short.

    Lange Antwort: Angenommen, du brauchst die ersten 2 Strukturen des unions:

    C-Quellcode

    1. struct freespace_message {
    2. int messageType;
    3. uint8_t ver; /**< HID protocol version */
    4. uint8_t len; /**< Length, used in version 2 only */
    5. uint8_t dest; /**< Destination, used in version 2 only */
    6. uint8_t src; /**< Source, used in version 2 only */
    7. union {
    8. struct freespace_PairingMessage pairingMessage;
    9. struct freespace_ProductIDRequest productIDRequest;
    10. }
    11. }


    Dann schreibst du in VB:

    VB.NET-Quellcode

    1. <StructLayout(LayoutKind.Explicit)>
    2. Structure FreespaceMessage
    3. <FieldOffset(0)>
    4. Public messageType As Int32 ' int
    5. <FieldOffset(4)>
    6. Public ver As Byte 'uint8_t
    7. <FieldOffset(5)>
    8. Public len As Byte 'uint8_t
    9. <FieldOffset(6)>
    10. Public dest As Byte 'uint8_t
    11. <FieldOffset(7)>
    12. Public src As Byte 'uint8_t
    13. <FieldOffset(8)>
    14. Public pairingMessage As PairingMessage
    15. ' gleicher Offset wie oben!
    16. <FieldOffset(8)>
    17. Public productIDRequest As ProductIDRequest
    18. End Structure
    19. <StructLayout(LayoutKind.Sequential)>
    20. Structure PairingMessage
    21. ' Bla
    22. End Structure
    23. <StructLayout(LayoutKind.Sequential)>
    24. Structure ProductIDRequest
    25. ' Bla
    26. End Structure


    Da das Array innerhalb einer Struktur deklariert und kein Zeiger ist, schreibst du in VB:

    VB.NET-Quellcode

    1. <StructLayout(LayoutKind.Sequential)>
    2. Structure MotionEngineOutput
    3. ' [...]
    4. Public sequenceNumber As UInt32
    5. <MarshalAs(UnmanagedType.ByValArray, SizeConst:=44)>
    6. Public meData() As Byte
    7. End Structure


    Für Arrays siehe auch: msdn.microsoft.com/de-de/library/z6cfh6e6(v=vs.110).aspx
    Gruß
    hal2000

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „hal2000“ ()

    @hal2000 vielen Dank für deine schnelle Antwort.

    Ich probiere das mal aus.

    Achtung: Bei mir sind die Member von freespace_message uint8_t, nicht uint16_t - bitte kontrollieren.

    ja da hast du Recht, da habe ich mich vertan.

    Nachtrag: also das mit den Einbinden weitere Strukturen funktioniert ganz gut.
    Allerdings habe ich ein Problem mit der Struktur MotionEngineOutput:

    freespace_MotionEngineOutput Struct ReferenceFreespace Messages
    Data Fields
    uint8_t formatSelect
    uint8_t ff0
    uint8_t ff1
    uint8_t ff2
    uint8_t ff3
    uint8_t ff4
    uint8_t ff5
    uint8_t ff6
    uint8_t ff7
    uint32_t sequenceNumber
    uint8_t meData [44]

    und zwar brauche ich die Struktur bei der Funktion
    LIBFREESPACE_API int freespace_util_getAcceleration (struct freespace_MotionEngineOutput const * meOutPkt, struct MultiAxisSensor * sensor )
    in der Import-Klasse:

    VB.NET-Quellcode

    1. <DllImport("libfreespace.dll", CallingConvention:=CallingConvention.Cdecl)>
    2. Public Shared Function freespace_util_getAcceleration(ByRef meOutPkt As freespace_MotionEngineOutput, ByRef sensor As MultiAxisSensor) As Int32
    3. End Function

    VB.NET-Quellcode

    1. 'Beschleunigung wird angezeigt
    2. Dim B_Nachricht As Sensor.freespace_MotionEngineOutput
    3. Dim Sensordaten_Beschleunigung As Sensor.MultiAxisSensor
    4. If Sensor.freespace_util_getAcceleration(B_Nachricht, Sensordaten_Beschleunigung) = 0 Then
    5. Console.Write("Hier die Beschleunigungsdaten")
    6. Console.WriteLine("Die x-Koordinate : " + Sensordaten_Beschleunigung.x)
    7. End If

    Beim Debuggen kommt dann nur bei B_Nachricht der Hinweis, dass die Variable 'B_Nachricht' is passed by reference before it has been assigned a value
    Was soll man damit anfangen?
    Kennt einer von Euch eine bessere Möglichkeit Sensorwerte anzeigen zu lassen? Irgendwie funktioniert das bei mir nicht. (Sorry man muss eine Schleife schreiben, in der man immer wieder Nachrichten senden, und diese dann liest.)
    Mal abgesehen vom besagten Hinweis, kommt kein Fehler auf.

    Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von „chris_2091“ ()

    @chris_2091 Setze mal in Deine DLL einen Haltepunkt rein und führe sie schrittweise aus, da kannst Du Dir die ankommenden Variablen sowie den Verlauf ansehen.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    VB-Fragen über PN / Konversation werden ignoriert!
    Also im deutschen Visual Studio steht da:
    Die m-Variable wird übergeben, bevor ihr ein Wert zugewiesen wird. Zur Laufzeit kann eine Nullverweisausnahme auftreten. Stellen Sie sicher, dass die Struktur oder alle Verweismember vor der Verwendung initialisiert werden.

    Soll heißen: Initialisiere das Array, denn es ist ein sogenannter Verweismember (Arrays sind Referenztypen, kein Werttypen).

    VB.NET-Quellcode

    1. m.meData = DirectCast(Array.CreateInstance(GetType(Byte), 44), Byte())
    Gruß
    hal2000
    Danke @RodFromGermany für den Tipp! Allerdings weiß ich nicht wie man einen Breakpoint in die dll packt. Einfach die dll öffnen geht nicht oder?

    hal2000 schrieb:

    Also im deutschen Visual Studio steht da:

    Die m-Variable wird übergeben, bevor ihr ein Wert zugewiesen wird. Zur Laufzeit kann eine Nullverweisausnahme auftreten. Stellen Sie sicher, dass die Struktur oder alle Verweismember vor der Verwendung initialisiert werden


    Ja, genau, das kam bei mir auch.
    Super! Danke @hal2000

    chris_2091 schrieb:

    Einfach die dll öffnen geht nicht oder?
    Ich nehme mal an, dass das Projekt der DLL der Projektmappe Deines Hauptprogramms angehört, da hast Du beide Projekte in derselben Entwicklungsumgebungs-Instanz.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    VB-Fragen über PN / Konversation werden ignoriert!
    Also ich habe die dll aus der Projektmappe gebaut, die man durch CMake bekommt, die Binaries habe ich von hier github.com/rpavlik/libfreespace

    Ich habe jetzt allerdings ein Problem mit einer Methode, beim Ausführen wird folgender Fehler:
    An unhandled exception of type 'System.NullReferenceException' occurred in Cursorsteuerung.exe
    Additional information: Der Objektverweis wurde nicht auf eine Objektinstanz festgelegt

    Dabei habe ich alle Objekte instanziert.
    Hier die Methode aus der Doku:

    LIBFREESPACE_API int freespace_readMessage (FreespaceDeviceId id, struct freespace_message * message, unsigned int timeoutMs )
    Read a message struct from the specified device. This function blocks until a message is received, there's a timeout or an error.
    Parameters
    id : the FreespaceDeviceId of the device to read from
    message : where to put the received message
    timeoutMs : the timeout in milliseconds or 0 to wait forever

    ich hab's so importiert

    VB.NET-Quellcode

    1. ' Nachricht vom Sensor lesen
    2. <DllImport("libfreespace.dll", CallingConvention:=CallingConvention.Cdecl)>
    3. Public Shared Function freespace_readMessage(ByVal FreespaceDeviceId As Int32, ByRef Info As FreespaceMessage, ByVal timeOutMs As Int32) As Int32
    4. End Function


    so sieht's bei mir:

    VB.NET-Quellcode

    1. Dim Nachricht As Sensor.FreespaceMessage
    2. Nachricht.messageType = 49 ' für das enum FREESPACE_MESSAGE_DATAMODECONTROLV2REQUEST
    3. Nachricht.dataModeControlV2Request.packetSelect = 8 '1 ist nur Cursorsteuerung und 8 nur für Daten
    4. Nachricht.dataModeControlV2Request.mode = 0 ' 0 heißt full motion
    5. Nachricht.dataModeControlV2Request.formatSelect = 0 'Setzen einiger Modi -> identisch denen aus Beispiel
    6. Nachricht.dataModeControlV2Request.ff0 = 1
    7. Nachricht.dataModeControlV2Request.ff3 = 1
    8. sendenAnSensor = Sensor.freespace_sendMessage(Sensor_device_id, Nachricht) 'senden der Nachricht

    VB.NET-Quellcode

    1. Dim quit = 0 ' Schleifenvariable wird jedes Mal hoch gezählt wenn Daten erfolgreich gesendet bis 20 -> Schleifenabbruch
    2. Dim Sensordaten_Beschleunigung As Sensor.MultiAxisSensor 'Paket das Beschleunigung in x,y,z und w hat
    3. If sendenAnSensor = 0 Then ' senden der Nachricht war erfolgreich
    4. While quit < 20 ' läuft solange bis 20 (wird beim Empfangen der Daten hoch gezählt)
    5. If Sensor.freespace_readMessage(Sensor_device_id, Nachricht, 100) = 0 Then 'erfolgreiches Lesen 100 sind ms die ein TimeOut verursachen->Fehler
    6. If Sensor.freespace_util_getAcceleration(Nachricht.motionEngineOutput, Sensordaten_Beschleunigung) = 0 Then ' Beschleunigung bekommen
    7. Console.WriteLine("Hier die Beschleunigung in x-Richtung: " + Sensordaten_Beschleunigung.x.ToString) 'Ausgabe
    8. quit = quit + 1 'hochzählen bei erfolgreichen Datentransfer
    9. End If
    10. End If
    11. End While
    12. End If


    Nachtrag:
    das Array aus der Struktur MotionEngingeOutput muss wie folgt definiert werden, wenn es Teil einer anderenStruktur sein soll

    VB.NET-Quellcode

    1. <StructLayout(LayoutKind.Sequential)>' für die Verwendung in der Struktur FreespaceMessage notwendig
    2. Public Structure freespace_DataModeControlV2Request ' aus der Doku
    3. 'blabla
    4. Public sequenceNumber As UInt32 'uint32_t
    5. <MarshalAs(UnmanagedType.ByValArray, SizeConst:=44)>'Setzen des Arrays
    6. Public Shared meData() As Byte = DirectCast(Array.CreateInstance(GetType(Byte), 44), Byte())'wichtig sonst gibt's einen Fehler in der anderen Struktur die diese Struktur benutzt








    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „chris_2091“ ()

    Edit: Tests haben gezeigt, dass der Code in diesem Post nicht funktioniert.

    Spoiler anzeigen

    Die Struktur freespace_DataModeControlV2Request besitzt keinen Arraymember. Warum deklarierst du einen? Hier nochmal die korrekten Deklarationen:

    VB.NET-Quellcode

    1. <StructLayout(LayoutKind.Explicit)>
    2. Structure FreespaceMessage
    3. <FieldOffset(0)>
    4. Public messageType As Int32
    5. <FieldOffset(4)>
    6. Public ver As Byte
    7. <FieldOffset(5)>
    8. Public len As Byte
    9. <FieldOffset(6)>
    10. Public dest As Byte
    11. <FieldOffset(7)>
    12. Public src As Byte
    13. <FieldOffset(8)>
    14. Public dataModeControlV2Request As DataModeControlV2Request
    15. <FieldOffset(8)>
    16. Public motionEngineOutput As MotionEngineOutput
    17. End Structure
    18. <StructLayout(LayoutKind.Sequential)>
    19. Structure DataModeControlV2Request
    20. Public operatingStatus As Byte
    21. Public mode As Int32
    22. Public outputStatus As Byte
    23. Public packetSelect As Byte
    24. Public formatSelect As Byte
    25. Public ff0 As Byte
    26. Public ff1 As Byte
    27. Public ff2 As Byte
    28. Public ff3 As Byte
    29. Public ff4 As Byte
    30. Public ff5 As Byte
    31. Public ff6 As Byte
    32. Public ff7 As Byte
    33. End Structure
    34. <StructLayout(LayoutKind.Sequential)>
    35. Structure MotionEngineOutput
    36. Public formatSelect As Byte
    37. Public ff0 As Byte
    38. Public ff1 As Byte
    39. Public ff2 As Byte
    40. Public ff3 As Byte
    41. Public ff4 As Byte
    42. Public ff5 As Byte
    43. Public ff6 As Byte
    44. Public ff7 As Byte
    45. Public sequenceNumber As UInt32
    46. <MarshalAs(UnmanagedType.ByValArray, SizeConst:=44)>
    47. Public meData() As Byte
    48. End Structure

    Du vermischst die gesendete und die empfangene Nachricht in derselben Variable --> schlecht. Beim Senden verwendest du den Array-Teil nicht. Die Warnung kannst du in diesem Fall so vermeiden:

    VB.NET-Quellcode

    1. Dim Nachricht As Sensor.FreespaceMessage = Nothing

    Nimm eine eigene Variable zum Empfangen von Nachrichten:

    VB.NET-Quellcode

    1. Dim rMsg As Sensor.FreespaceMessage
    2. rMsg.motionEngineOutput.meData = DirectCast(Array.CreateInstance(GetType(Byte), 44), Byte())
    3. ' While...
    4. Sensor.freespace_readMessage(Sensor_device_id, rMsg, 100)
    5. ' End While


    Gruß
    hal2000

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „hal2000“ ()

    Danke @hal2000

    hal2000 schrieb:

    Die Struktur freespace_DataModeControlV2Request besitzt keinen Arraymember. Warum deklarierst du einen? Hier nochmal die korrekten Deklarationen:

    Ja das Problem ist wenn ich das so mache wie Du es hier vorschlägst kommt folgende Fehlermeldung:
    An unhandled exception of type 'System.TypeLoadException' occurred in System.Windows.Forms.dll

    Additional information: Der Typ "FreespaceMessage" der Assembly "Cursorsteuerung, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" konnte nicht geladen werden, da sie bei Offset 8 ein Objektfeld enthält, das falsch ausgerichtet ist oder von einem Feld überlappt wird, das kein Objektfeld ist.


    Sorry habe hier einen Fehler gemacht

    chris_2091 schrieb:

    <StructLayout(LayoutKind.Sequential)>' für die Verwendung in der Struktur FreespaceMessage notwendig
    Public Structure freespace_DataModeControlV2Request ' aus der Doku
    'blabla
    Public sequenceNumber As UInt32 'uint32_t
    <MarshalAs(UnmanagedType.ByValArray, SizeConst:=44)>'Setzen des Arrays
    Public Shared meData() As Byte = DirectCast(Array.CreateInstance(GetType(Byte), 44), Byte())'wichtig sonst gibt's einen Fehler in der anderen Struktur

    es müsste in die

    VB.NET-Quellcode

    1. Structure MotionEngineOutput
    und nicht in

    VB.NET-Quellcode

    1. Structure DataModeControlV2Request


    Wenn ich jetzt allerdings Instanzierung in der Strukturdefinition mache und für das Lesen wie @hal2000 einen neuen freespace_message definiere, läuft das Programm und wirft eine Exception.
    An unhandled exception of type 'System.AccessViolationException' occurred in Cursorsteuerung.exe
    Additional information: Es wurde versucht, im geschützten Speicher zu lesen oder zu schreiben. Dies ist häufig ein Hinweis darauf, dass anderer Speicher beschädigt ist.

    ich denke, dass das daran liegt ein Pointer erwartet wird laut Doku ist message where to put the received message

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „chris_2091“ ()

    chris_2091 schrieb:

    TypeLoadException

    Ok, das ist eine Einschränkung des Frameworks, wie ich grade lese. Wieder was gelernt. In diesem Fall muss das Union aufgesplittet werden:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. <StructLayout(LayoutKind.Sequential)>
    2. Structure DataModeControlV2RequestMessage
    3. ' FreespaceMessage members
    4. Public messageType As Int32
    5. Public ver As Byte
    6. Public len As Byte
    7. Public dest As Byte
    8. Public src As Byte
    9. ' Union members
    10. Public operatingStatus As Byte
    11. Public mode As Int32
    12. Public outputStatus As Byte
    13. Public packetSelect As Byte
    14. Public formatSelect As Byte
    15. Public ff0 As Byte
    16. Public ff1 As Byte
    17. Public ff2 As Byte
    18. Public ff3 As Byte
    19. Public ff4 As Byte
    20. Public ff5 As Byte
    21. Public ff6 As Byte
    22. Public ff7 As Byte
    23. End Structure
    24. <StructLayout(LayoutKind.Sequential)>
    25. Structure MotionEngineOutputMessage
    26. ' FreespaceMessage members
    27. Public messageType As Int32
    28. Public ver As Byte
    29. Public len As Byte
    30. Public dest As Byte
    31. Public src As Byte
    32. ' Union members
    33. Public formatSelect As Byte
    34. Public ff0 As Byte
    35. Public ff1 As Byte
    36. Public ff2 As Byte
    37. Public ff3 As Byte
    38. Public ff4 As Byte
    39. Public ff5 As Byte
    40. Public ff6 As Byte
    41. Public ff7 As Byte
    42. Public sequenceNumber As UInt32
    43. <MarshalAs(UnmanagedType.ByValArray, SizeConst:=44)>
    44. Public meData() As Byte
    45. End Structure

    Möglicherweise geht das auch über Vererbung, um das Kopieren der FreespaceMessage-Member zu vermeiden. Probiers mal aus:

    Spoiler anzeigen

    VB.NET-Quellcode

    1. <StructLayout(LayoutKind.Sequential)>
    2. Class FreespaceMessage
    3. Public messageType As Int32
    4. Public ver As Byte
    5. Public len As Byte
    6. Public dest As Byte
    7. Public src As Byte
    8. End Class
    9. <StructLayout(LayoutKind.Sequential)>
    10. Class DataModeControlV2RequestMessage
    11. Inherits FreespaceMessage
    12. Public operatingStatus As Byte
    13. Public mode As Int32
    14. Public outputStatus As Byte
    15. Public packetSelect As Byte
    16. Public formatSelect As Byte
    17. Public ff0 As Byte
    18. Public ff1 As Byte
    19. Public ff2 As Byte
    20. Public ff3 As Byte
    21. Public ff4 As Byte
    22. Public ff5 As Byte
    23. Public ff6 As Byte
    24. Public ff7 As Byte
    25. End Class
    26. <StructLayout(LayoutKind.Sequential)>
    27. Class MotionEngineOutputMessage
    28. Inherits FreespaceMessage
    29. Public formatSelect As Byte
    30. Public ff0 As Byte
    31. Public ff1 As Byte
    32. Public ff2 As Byte
    33. Public ff3 As Byte
    34. Public ff4 As Byte
    35. Public ff5 As Byte
    36. Public ff6 As Byte
    37. Public ff7 As Byte
    38. Public sequenceNumber As UInt32
    39. <MarshalAs(UnmanagedType.ByValArray, SizeConst:=44)>
    40. Public meData() As Byte
    41. End Class


    In jedem Fall brauchst du aber je eine Überladung für jede Struktur, damit du die native Funktion mit dem passenden Typ aufrufen kannst. Vergiss bei der Variante mit den Klassen nicht, dass das ByRef weg muss und ein <Out()> als Attribut vor den Parameter gehört (siehe msdn.microsoft.com/de-de/library/23acw07k(v=vs.110).aspx).

    chris_2091 schrieb:

    ich denke, dass das daran liegt ein Pointer erwartet wird

    Das erledigt das ByRef automatisch. Gerade durch obiges Problem könnte man aber in Betracht ziehen, die Funktion mit einem IntPtr-Parameter zu deklarieren und das Marshalling manuell zu machen. Aber der Aufwand bleibt trotzdem erheblich.
    Gruß
    hal2000

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „hal2000“ ()

    Danke dir @hal2000 !!

    Ich probiere das mal aus. Hoffe, dass es endlich klappt. ;)

    Also für die Strukturdefinition muss wie folgt lauten:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. <StructLayout(LayoutKind.Explicit)>
    2. Structure FreespaceMessage
    3. <FieldOffset(0)>
    4. Public messageType As Int32
    5. <FieldOffset(4)>
    6. Public ver As Byte
    7. <FieldOffset(5)>
    8. Public len As Byte
    9. <FieldOffset(6)>
    10. Public dest As Byte
    11. <FieldOffset(7)>
    12. Public src As Byte
    13. <FieldOffset(8)>
    14. Public dataModeControlV2Request As DataModeControlV2Request
    15. <FieldOffset(32)>
    16. Public motionEngineOutput As MotionEngineOutput
    17. End Structure

    DataModeControlV2Request nimmt 24 Bytes ein, daher muss die nächste Struktur auf 32 usw.

    Leider funktioniert das Nachrichten empfangen immer noch nicht, dabei habe ich mich sehr an das Herstellerbeispiel gehalten, den relevanten Code sieht ihr hier:
    Spoiler anzeigen

    C-Quellcode

    1. /**
    2. * This file is part of libfreespace-examples.
    3. *
    4. * Copyright (c) 2009-2013, Hillcrest Laboratories, Inc.
    5. * All rights reserved.
    6. */
    7. struct freespace_message message;
    8. FreespaceDeviceId device;
    9. int numIds; // The number of device ID found
    10. int rc; // Return code
    11. struct MultiAxisSensor angVel;
    12. // Configure the device for motion outputs
    13. printf("Sending message to enable motion data.\n");
    14. memset(&message, 0, sizeof(message)); // Make sure all the message fields are initialized to 0.
    15. message.messageType = FREESPACE_MESSAGE_DATAMODECONTROLV2REQUEST;
    16. message.dataModeControlV2Request.packetSelect = 8; // MotionEngine Outout
    17. message.dataModeControlV2Request.mode = 0; // Set full motion
    18. message.dataModeControlV2Request.formatSelect = 0; // MEOut format 0
    19. message.dataModeControlV2Request.ff0 = 1; // Pointer fields
    20. message.dataModeControlV2Request.ff3 = 1; // Angular velocity fields
    21. rc = freespace_sendMessage(device, &message);
    22. if (rc != FREESPACE_SUCCESS) {
    23. printf("Could not send message: %d.\n", rc);
    24. }
    25. // A loop to read messages
    26. printf("Listening for messages.\n");
    27. while (!quit) {
    28. rc = freespace_readMessage(device, &message, 100);
    29. if (rc == FREESPACE_ERROR_TIMEOUT ||
    30. rc == FREESPACE_ERROR_INTERRUPTED) {
    31. // Both timeout and interrupted are ok.
    32. // Timeout happens if there aren't any events for a second.
    33. // Interrupted happens if you type CTRL-C or if you
    34. // type CTRL-Z and background the app on Linux.
    35. continue;
    36. }
    37. if (rc != FREESPACE_SUCCESS) {
    38. printf("Error reading: %d. Quitting...\n", rc);
    39. break;
    40. }
    41. // freespace_printMessage(stdout, &message); // This just prints the basic message fields
    42. if (message.messageType == FREESPACE_MESSAGE_MOTIONENGINEOUTPUT) {
    43. rc = freespace_util_getAngularVelocity(&message.motionEngineOutput, &angVel);
    44. if (rc == 0) {
    45. printf ("X: % 6.2f, Y: % 6.2f, Z: % 6.2f\n", angVel.x, angVel.y, angVel.z);
    46. }
    47. }
    48. }

    Ich habe daraus in vb-net folgendes gemacht:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. 'Auslesen der Daten
    2. '*****************************************************************
    3. Dim Nachricht As Sensor.FreespaceMessage 'Nachricht definieren
    4. Nachricht.motionEngineOutput.meData = DirectCast(Array.CreateInstance(GetType(Byte), 44), Byte()) 'Array der Struktur instanzieren
    5. 'memset(& Message, 0, sizeof(Message)); // Make sure all the message fields are initialized To 0.
    6. 'Wie setzt man das am besten in vb um?
    7. 'Dim ip1 As IntPtr = Marshal.AllocHGlobal(Marshal.SizeOf(Nachricht)) ' Setzen der jeweiligen Zeiger
    8. 'Sensor.MemSet(ip1, 0, Marshal.SizeOf(Nachricht)) ' alle Felder auf 0 setzen
    9. 'Marshal.FreeHGlobal(ip1) ' Zeiger freigeben
    10. 'Setzen der richtigen Flags
    11. Nachricht.messageType = 49 ' für das enum FREESPACE_MESSAGE_DATAMODECONTROLV2REQUEST
    12. Nachricht.dataModeControlV2Request.packetSelect = 8 '1 ist nur Cursorsteuerung und 8 nur für Daten, 9 für beides
    13. Nachricht.dataModeControlV2Request.mode = 0 ' 0 heißt full motion andere 1-sleep, 2-deep sleep, 3-deep deep sleep, 4-full motion on
    14. Nachricht.dataModeControlV2Request.formatSelect = 0 'alles wie beim Beispiel gesetzt
    15. Nachricht.dataModeControlV2Request.ff0 = 1 'Pointer fields
    16. Nachricht.dataModeControlV2Request.ff3 = 1 'Angular velocity fields
    17. sendenAnSensor = Sensor.freespace_sendMessage(Sensor_device_id, Nachricht) 'senden der Nachricht
    18. Dim quit = 0 ' Schleifenvariable h
    19. If sendenAnSensor = 0 Then ' senden der Nachricht war erfolgreich
    20. Dim rMsg As Sensor.FreespaceMessage '
    21. rMsg.motionEngineOutput.meData = DirectCast(Array.CreateInstance(GetType(Byte), 44), Byte()) 'Array instanzieren
    22. Dim Sensordaten_Beschleunigung As Sensor.MultiAxisSensor 'Paket in das die Winkelgeschwindigkeiten in x,y,z und w kommen
    23. Console.Write("Hier die Winkelgeschwindigkeit :")
    24. While quit < 100 ' läuft solange bis 100 (wird beim Empfangen der Daten hoch gezählt) oder falls Fehlermeldung kommt
    25. Dim nachrichtStatus = Sensor.freespace_readMessage(Sensor_device_id, rMsg, 100) 'Nachricht wird gelesen
    26. 'Überprüfen ob Nachricht erfolgreich gelesen wurde
    27. If (nachrichtStatus = -7) Or (nachrichtStatus = -10) Then 'Im Orginal enums : -7 heißt FREESPACE_ERROR_TIMEOUT ;-10 heißt FREESPACE_ERROR_INTERRUPTED
    28. Continue While
    29. End If
    30. If Not (nachrichtStatus = 0) Then 'anderer Fehler beim Lesen
    31. Console.WriteLine("!!! Fehlermeldung: " + rc.ToString + "!!!") 'Zahl sagt was über den Fehler aus
    32. Exit While
    33. End If
    34. If (nachrichtStatus = 0) Then 'erfolgreiches Lesen 0 heißt FREESPACE_SUCCESS
    35. If rMsg.messageType = 56 Then ' 56 steht für FREESPACE_MESSAGE_MOTIONENGINEOUTPUT
    36. If Sensor.freespace_util_getAngularVelocity(rMsg.motionEngineOutput, Sensordaten_Beschleunigung) = 0 Then '
    37. Console.WriteLine("Hier die Winkelgeschwindigkeit in x: " + Sensordaten_Beschleunigung.x.ToString) '
    38. Console.WriteLine("Hier die Winkelgeschwindigkeit in y: " + Sensordaten_Beschleunigung.y.ToString)
    39. Console.WriteLine("Hier die Winkelgeschwindigkeit in z: " + Sensordaten_Beschleunigung.z.ToString)
    40. Console.WriteLine("***********Hier kommt eine neue Messung ******************") 'Trennen der Daten
    41. quit = quit + 1 'hochzählen bei erfolgreichen Datentransfer
    42. End If
    43. End If
    44. End If
    45. End While
    46. End If

    Das Senden der Nachricht ist wohl kein Problem, denn wenn man das Paket ändert (packetSelect = 1), sodass der Cursor durch den Sensor gesteuert werden soll, funktioniert das problemlos.
    Aber da muss man auch nicht eine Nachricht lesen.
    Bei dem Code zeigt die Console für alle Daten nur null an, obwohl ich den Sensor bewege.
    Ich denke, dass das Problem mit der Methode memset zusammen liegt, die in dem Beispielcode verwendet wird.
    Die Methode setzt alles auf einen Wert(hier null), sodass nirgends radom Sachen herumliegen.
    memset findet man in der msvcrt.dll siehe dazu
    pinvoke.net/default.aspx/msvcrt.memset
    Die dll habe ich auf meinem Rechner gefunden und entsprechend eingebunden wie es im Link gezeigt wird, im Programm sieht so aus

    VB.NET-Quellcode

    1. 'memset(& Message, 0, sizeof(Message)); // Make sure all the message fields are initialized To 0.
    2. Dim ip1 As IntPtr = Marshal.AllocHGlobal(Marshal.SizeOf(Nachricht)) ' Setzen der jeweiligen Zeiger
    3. Sensor.MemSet(ip1, 0, Marshal.SizeOf(Nachricht)) ' alle Felder auf 0 setzen
    4. Marshal.FreeHGlobal(ip1) ' Zeiger freigeben


    Leider stürzt das Programm beim Aufrufen ab
    vshost32.exe funktioniert nicht mehr

    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „chris_2091“ ()

    Ich habe jetzt endlich den Fehler gefunden und zwar soll man, wenn man nicht C genommen hat, andere Funktionen verwenden, freespace_private_send und freespace_private_read
    Spoiler anzeigen
    LIBFREESPACE_API int freespace_private_send (FreespaceDeviceId id, const uint8_t * message, int length )
    Send a message to the specified Freespace device synchronously. Deprecated for external use. For use with other language bindings, such as Python and Java, only.
    Parameters: id-the FreespaceDeviceId of the device to send message to
    message-the message to send
    length-the length of the message
    ReturnsFREESPACE_SUCCESS=0 or an error

    LIBFREESPACE_API int freespace_private_read (FreespaceDeviceId id, uint8_t * message, int maxLength, unsigned int timeoutMs, int * actualLength )
    Read a message from the specified device. This function blocks until a message is received, there's a timeout or an error. Deprecated for external use. For use with other language bindings, such as Python and Java, only.
    Parameters: id-the FreespaceDeviceId of the device to read from
    message-where to put the received message
    maxLength-the max length of the message
    timeoutMs-the timeout in milliseconds or 0 to wait forever
    actualLength-the number of bytes received
    ReturnsFREESPACE_SUCCESS or an error


    Jetzt weiß ich allerdings nicht wie man die Nachricht definiert, um es dann zu verschicken.
    Vorher hatte man Strukturen, wo man einzelne Werte zuweisen konnte.
    Auch weiß ich nicht wie man am besten die Nachricht an andere Funktionen übergebe:
    wie zum Beispiel:

    VB.NET-Quellcode

    1. <DllImport("libfreespace.dll", CallingConvention:=CallingConvention.Cdecl)>
    2. Public Shared Function freespace_util_getAcceleration(ByRef meOutPkt As MotionEngineOutput, ByRef sensor As MultiAxisSensor) As Int32
    3. End Function

    hier war ja meOutPkt vom Typ MotionEngineOutput, was wiederum ein Teil der Nachricht war.
    Leider ist die Doku in der Hinsicht nicht wirklich hilfreich, da offiziell nur C unterstützt wird.
    Spoiler anzeigen

    VB.NET-Quellcode

    1. 'Definition der neuen Funktionen
    2. ' Winkelgeschwindigkeit bekommen
    3. <DllImport("libfreespace.dll", CallingConvention:=CallingConvention.Cdecl)>
    4. Public Shared Function freespace_util_getAngularVelocity(ByRef meOutPkt As Byte, ByRef sensor As MultiAxisSensor) As Int32
    5. End Function
    6. ' Nachricht vom Sensor lesen
    7. <DllImport("libfreespace.dll", CallingConvention:=CallingConvention.Cdecl)>
    8. Public Shared Function freespace_private_read(ByVal FreespaceDeviceId As Int32, ByRef Info As Byte, ByVal maxLength As Int32, ByVal timeOutMs As Int32, ByRef actualLength As Int32) As Int32
    9. End Function
    10. 'Auslesen der Daten
    11. '*****************************************************************
    12. Dim Nachricht As Sensor.FreespaceMessage 'Nachricht definieren
    13. Nachricht.motionEngineOutput.meData = DirectCast(Array.CreateInstance(GetType(Byte), 44), Byte()) 'Array der Struktur motionEngineOutput instanzieren
    14. 'Setzen der richtigen Flags
    15. Nachricht.messageType = 49 ' für das enum FREESPACE_MESSAGE_DATAMODECONTROLV2REQUEST
    16. Nachricht.dataModeControlV2Request.packetSelect = 8 '1 ist nur Cursorsteuerung und 8 nur für Daten, 9 für beides
    17. Nachricht.dataModeControlV2Request.mode = 0 ' 0 heißt full motion andere sind 1 - sleep, 2 - deep sleep, 3 - deep deep sleep, 4 - full motion on, 5 - notify on motion
    18. Nachricht.dataModeControlV2Request.formatSelect = 0 '
    19. Nachricht.dataModeControlV2Request.ff0 = 1 'Pointer fields
    20. Nachricht.dataModeControlV2Request.ff3 = 1 'Angular velocity fields
    21. sendenAnSensor = Sensor.freespace_sendMessage(Sensor_device_id, Nachricht) 'senden der Nachricht
    22. Dim quit = 0 ' Schleifenvariable wird jedes Mal hoch gezählt wenn Daten erfolgreich gesendet bis 20 -> Schleifenabbruch
    23. If sendenAnSensor = 0 Then ' senden der Nachricht war erfolgreich
    24. Dim rMsg As Byte
    25. Dim Nachrichtlaenge As Integer
    26. Dim maxLength As Integer
    27. Dim Sensordaten_Beschleunigung As Sensor.MultiAxisSensor 'Paket in das die Winkelgeschwindigkeiten in x,y,z und w kommen
    28. Console.Write("Hier die Winkelgeschwindigkeit :")
    29. While quit < 100 ' läuft solange bis 100 (wird beim Empfangen der Daten hoch gezählt) oder falls Fehlermeldung kommt
    30. Dim nachrichtStatus = Sensor.freespace_private_read(Sensor_device_id, rMsg, maxLength, 100, Nachrichtlaenge)'Nachricht wird gelesen
    31. Console.WriteLine("Die neue Nachricht hat eine Länge von " + Nachrichtlaenge.ToString)
    32. 'Überprüfen ob Nachricht erfolgreich gelesen wurde
    33. If (nachrichtStatus = -7) Or (nachrichtStatus = -10) Then 'Im Orginal enums : -7 heißt FREESPACE_ERROR_TIMEOUT ; -10 heißt FREESPACE_ERROR_INTERRUPTED
    34. Continue While
    35. End If
    36. If Not (nachrichtStatus = 0) Then 'anderer Fehler beim Lesen
    37. Console.WriteLine("!!! Fehlermeldung: " + rc.ToString + "!!!") 'Zahl sagt was über den Fehler aus
    38. Exit While
    39. End If
    40. If (nachrichtStatus = 0) Then 'erfolgreiches Lesen 0 heißt FREESPACE_SUCCESS
    41. 'If rMsg.messageType = 56 Then ' 56 steht für FREESPACE_MESSAGE_MOTIONENGINEOUTPUT
    42. If Sensor.freespace_util_getAngularVelocity(rMsg, Sensordaten_Beschleunigung) = 0 Then ' Beschleunigung bekommen
    43. Console.WriteLine("Hier die Winkelgeschwindigkeit in x: " + Sensordaten_Beschleunigung.x.ToString) 'Winkelgeschwindigkeit in (deg/s)
    44. Console.WriteLine("Hier die Winkelgeschwindigkeit in y: " + Sensordaten_Beschleunigung.y.ToString) 'Winkelgeschwindigkeit in (deg/s)
    45. Console.WriteLine("Hier die Winkelgeschwindigkeit in z: " + Sensordaten_Beschleunigung.z.ToString) 'Winkelgeschwindigkeit in (deg/s)
    46. Console.WriteLine("***********Hier kommt eine neue Messung ******************") 'Trennen der Daten
    47. quit = quit + 1 'hochzählen bei erfolgreichen Datentransfer
    48. End If
    49. 'End If
    50. End If
    51. End While
    52. End If
    53. End Sub


    das ganze läuft jetzt durch und er zeigt mir bei 100 Durchläufen nur die gleichen Werte an, allerdings halbwegs sinnvolle

    Nachtrag:
    ich habe einfach folgendes hinzugefügt

    VB.NET-Quellcode

    1. While quit < 100 ' läuft solange bis 100 (wird beim Empfangen der Daten hoch gezählt) oder falls Fehlermeldung kommt
    2. Dim nachrichtStatus = Sensor.freespace_private_read(Sensor_device_id, rMsg, maxLength, 100, Nachrichtlaenge)'Nachricht wird gelesen
    3. Console.WriteLine("Die neue Nachricht hat eine Länge von " + Nachrichtlaenge.ToString)'hinzugefügt

    Die Konsole gibt aus, dass die Nachrichtenlänge bei allen Durchläufen nur null ist.


    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „chris_2091“ ()

    Sorry für die späte Antwort - das Forum zeigt Editierungen nicht als neue Beiträge an, deshalb habe ich erst den jetzigen Beitrag gesehen.

    chris_2091 schrieb:

    DataModeControlV2Request nimmt 24 Bytes ein, daher muss die nächste Struktur auf 32 usw.

    Nein - alle Member einer C-Union fangen bei derselben Startadresse an. Siehe stackoverflow.com/questions/9834395/memory-layout-c-union:

    Every member of a union has the same starting address; different members
    may have different sizes. The size of the union as a whole is at least the maximum size of any member; there may be extra padding at the end for alignment requirements.

    Der Aufruf an memset ist korrekt und läuft bei mir auch durch. Er ist übrigens nicht erforderlich, weil der Puffer sowieso überschrieben wird; siehe freespace_device.c, Z. 816.

    chris_2091 schrieb:

    Jetzt weiß ich allerdings nicht wie man die Nachricht definiert, um es dann zu verschicken.

    Lies mal den Quellcode der Implementierung von freespace_readMessage. Überraschung: Du brauchst einen weiteren API-Aufruf, um den Byte-Puffer in eine Datenstruktur zu übersetzen, und zwar genau die Datenstruktur, die du auch für die Benutzung von freespace_readMessage deklarieren musst. Damit drehst du dich nur im Kreis.

    Dein Projekt steht und fällt mit der Deklaration der Nachrichtenstrukturen. Mangels Hardware kann ich nur den Beginn der Aufrufe testen, d.h. den ersten Transit von .NET in die DLL. Solange das Programm mit den Deklarationen aus Post #32 nicht abstürzt, solltest du mal den Debugger bemühen, um in den Datenpuffer rt->buffer_ reinzuschauen, bevor er in die Strukturen zurückkopiert wird. Dann kannst du auch überprüfen, ob die Längen der Strukturen passen. Wenn allerdings actualLength immer 0 ist, scheint etwas mit dem Gerät oder dem DLL-Code nicht in Ordnung zu sein, denn dieser Wert kommt direkt aus der Warteschlange der Empfangsroutine. Dann kommst du nur mit Debugging der DLL-Routinen weiter.

    Edit: Ist es überhaupt schonmal vorgekommen, dass freespace_readMessage als Status 0 zurückgegeben hat? Was sind in diesem Fall die Rohdaten in rMsg? Setze vor das Continue While in Zeile 29 mal ein Thread.Sleep(250), damit du den Sensor nicht überforderst, indem du ihn mit Kommandos bombardierst. Entweder stimmen die zurückgegebenen Daten in rMsg nicht, oder die falsche Strukturdeklaration würfelt das Ergebnis durcheinander, sodass freespace_util_getAngularVelocity falsche Eingabedaten bekommt. Letzterer Fall ist wahrscheinlicher, weil die Funktion auf die leeren 24 Byte in rMsg.dataModeControlV2Request zugreift und daher 0 für alle Werte zurückgibt.

    OffTopic: Crossposting in verschiedenen Foren ist nicht gerade nett.
    Gruß
    hal2000

    Dieser Beitrag wurde bereits 7 mal editiert, zuletzt von „hal2000“ ()

    es scheint zu funktionieren!! :D

    hal2000 schrieb:

    Dein Projekt steht und fällt mit der Deklaration der Nachrichtenstrukturen.

    Genau das war das Problem. Ich habe die Struktur Freespace_Message in zwei Strukturen aufgeteilt, sodass man eine Struktur fürs Senden einer Nachricht und einen fürs Empfangen einer Nachricht bekommt.

    Hier sieht man den Code:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. ' für das Senden von Nachrichten benötigte Struktur
    2. <StructLayout(LayoutKind.Explicit)>
    3. Structure FreespaceMessage_Request
    4. <FieldOffset(0)>
    5. Public messageType As Int32
    6. <FieldOffset(4)>
    7. Public ver As Byte
    8. <FieldOffset(5)>
    9. Public len As Byte
    10. <FieldOffset(6)>
    11. Public dest As Byte
    12. <FieldOffset(7)>
    13. Public src As Byte
    14. <FieldOffset(8)>
    15. Public dataModeControlV2Request As DataModeControlV2Request
    16. End Structure
    17. <StructLayout(LayoutKind.Sequential)>
    18. Structure DataModeControlV2Request
    19. Public operatingStatus As Byte
    20. Public mode As Int32
    21. Public outputStatus As Byte
    22. Public packetSelect As Byte
    23. Public formatSelect As Byte
    24. Public ff0 As Byte
    25. Public ff1 As Byte
    26. Public ff2 As Byte
    27. Public ff3 As Byte
    28. Public ff4 As Byte
    29. Public ff5 As Byte
    30. Public ff6 As Byte
    31. Public ff7 As Byte
    32. End Structure
    33. ' für das Lesen von Nachrichten benötigte Struktur
    34. <StructLayout(LayoutKind.Explicit)>
    35. Structure FreespaceMessage_Read
    36. <FieldOffset(0)>
    37. Public messageType As Int32
    38. <FieldOffset(4)>
    39. Public ver As Byte
    40. <FieldOffset(5)>
    41. Public len As Byte
    42. <FieldOffset(6)>
    43. Public dest As Byte
    44. <FieldOffset(7)>
    45. Public src As Byte
    46. <FieldOffset(8)>
    47. Public motionEngineOutput As MotionEngineOutput
    48. End Structure
    49. <StructLayout(LayoutKind.Sequential)>
    50. Structure MotionEngineOutput
    51. Public formatSelect As Byte
    52. Public ff0 As Byte
    53. Public ff1 As Byte
    54. Public ff2 As Byte
    55. Public ff3 As Byte
    56. Public ff4 As Byte
    57. Public ff5 As Byte
    58. Public ff6 As Byte
    59. Public ff7 As Byte
    60. Public sequenceNumber As UInt32
    61. <MarshalAs(UnmanagedType.ByValArray, SizeConst:=44)>
    62. Public meData() As Byte
    63. End Structure

    Eine einfache Unterteilung wie es @hal2000 in einem vorherigen Post gemacht, funktioniert nicht da die Funktion freespace_util_getAngularVelocityein Strukturpaket braucht, in dem Fall MotionEngineOutput.

    hal2000 schrieb:

    Ist es überhaupt schonmal vorgekommen, dass freespace_readMessage als Status 0 zurückgegeben hat?

    In der Regel schon, allerdings hat die Funktion freespace_util_getAngularVelocity nicht null als Status zurückgegeben, daher war da etwas faul.
    Ich denke, dass wohl die Eingangsdaten falsch waren.
    Jetzt taucht dieser Fehler nie auf, den funktionierenden Code poste ich mal hier:
    Spoiler anzeigen

    VB.NET-Quellcode

    1. '*****************************************************************
    2. 'Auslesen der Daten
    3. '*****************************************************************
    4. Dim Nachricht As Sensor.FreespaceMessage_Request 'Nachricht definieren
    5. 'memset(& Message, 0, sizeof(Message)); // Make sure all the message fields are initialized To 0.
    6. 'Wie setzt man das am besten in vb um?
    7. 'Dim ip1 As IntPtr = Marshal.AllocHGlobal(Marshal.SizeOf(Nachricht)) ' Setzen der jeweiligen Zeiger
    8. 'Sensor.MemSet(ip1, 0, Marshal.SizeOf(Nachricht)) ' alle Felder auf 0 setzen
    9. 'Marshal.FreeHGlobal(ip1) ' Zeiger freigeben
    10. 'Setzen der richtigen Flags
    11. Nachricht.messageType = 49 ' für das enum FREESPACE_MESSAGE_DATAMODECONTROLV2REQUEST
    12. Nachricht.dataModeControlV2Request.packetSelect = 8 '1 ist nur Cursorsteuerung und 8 nur für Daten, 9 für beides
    13. Nachricht.dataModeControlV2Request.mode = 0 ' 0 heißt full motion andere sind 1 - sleep, 2 - deep sleep, 3 - deep deep sleep, 4 - full motion on, 5 - notify on motion
    14. Nachricht.dataModeControlV2Request.formatSelect = 0 '
    15. Nachricht.dataModeControlV2Request.ff0 = 1 'Pointer fields
    16. Nachricht.dataModeControlV2Request.ff3 = 1 'Angular velocity fields
    17. sendenAnSensor = Sensor.freespace_sendMessage(Sensor_device_id, Nachricht) 'senden der Nachricht
    18. Dim quit = 0 ' Schleifenvariable wird jedes Mal hoch gezählt wenn Daten erfolgreich gesendet bis 20 -> Schleifenabbruch
    19. If sendenAnSensor = 0 Then ' senden der Nachricht war erfolgreich
    20. Dim rMsg As Sensor.FreespaceMessage_Read
    21. rMsg.motionEngineOutput.meData = DirectCast(Array.CreateInstance(GetType(Byte), 44), Byte()) 'Array der Struktur motionEngineOutput instanzieren
    22. Dim Sensordaten_Beschleunigung As Sensor.MultiAxisSensor 'Paket in das die Winkelgeschwindigkeiten in x,y,z und w kommen
    23. Console.Write("Hier die Winkelgeschwindigkeit :")
    24. While quit < 250 ' läuft solange bis 10 (wird beim Empfangen der Daten hoch gezählt)
    25. Dim nachrichtStatus = Sensor.freespace_readMessage(Sensor_device_id, rMsg, 100) 'Nachricht wird gelesen
    26. Console.WriteLine("Das Paket hat folgende Eigenschaften " + rMsg.motionEngineOutput.meData.ToString)
    27. Console.WriteLine("Die Sequenznummer beträgt: " + rMsg.motionEngineOutput.sequenceNumber.ToString)
    28. 'Überprüfen ob Nachricht erfolgreich gelesen wurde
    29. If (nachrichtStatus = -7) Or (nachrichtStatus = -10) Then 'Im Orginal enums : -7 heißt FREESPACE_ERROR_TIMEOUT ; -10 heißt FREESPACE_ERROR_INTERRUPTED
    30. System.Threading.Thread.Sleep(250)
    31. Console.WriteLine("ein Timeout oder Interrupted Fehler")
    32. Console.WriteLine("***********Hier kommt eine neue Messung ******************") 'ansonsten keine Trennung zu nächstem Schleifendurchlauf
    33. Continue While
    34. End If
    35. If Not (nachrichtStatus = 0) Then 'anderer Fehler beim Lesen
    36. Console.WriteLine("!!! Fehlermeldung: " + rc.ToString + "!!!") 'Zahl sagt was über den Fehler aus
    37. Exit While
    38. End If
    39. If (nachrichtStatus = 0) Then 'erfolgreiches Lesen 0 heißt FREESPACE_SUCCESS
    40. If rMsg.messageType = 56 Then ' 56 steht für FREESPACE_MESSAGE_MOTIONENGINEOUTPUT
    41. If Sensor.freespace_util_getAngularVelocity(rMsg.motionEngineOutput, Sensordaten_Beschleunigung) = 0 Then ' Beschleunigung bekommen
    42. Console.WriteLine("Hier die Winkelgeschwindigkeit in x: " + Sensordaten_Beschleunigung.x.ToString) 'Winkelgeschwindigkeit in (deg/s)
    43. Console.WriteLine("Hier die Winkelgeschwindigkeit in y: " + Sensordaten_Beschleunigung.y.ToString) 'Winkelgeschwindigkeit in (deg/s)
    44. Console.WriteLine("Hier die Winkelgeschwindigkeit in z: " + Sensordaten_Beschleunigung.z.ToString) 'Winkelgeschwindigkeit in (deg/s)
    45. quit = quit + 1 'hochzählen bei erfolgreichen Datentransfer
    46. Else
    47. Console.WriteLine("Winkelgeschwindigkeit nicht richtig gelesen")
    48. End If
    49. Else
    50. Console.WriteLine("falscher Nachrichtentyp (message_type != 56)")
    51. End If
    52. End If
    53. Console.WriteLine("***********Hier kommt eine neue Messung ******************") 'Trennen der Daten
    54. 'System.Threading.Thread.Sleep(250)
    55. Sensor.freespace_flush(Sensor_device_id) 'alte Nachricht löschen (ohne sehr lange Laufzeit->Fehler Winkelgeschwindigkeit falsch gelesen)
    56. End While
    57. End If

    An diesen Post habe ich mal ein Bild gepostet, was das System so rausspukt, es sind halbwegs sinnvolle Werte.
    Ich habe das mit mehreren Sensorbewegungen getestet und es werden die entsprechenden Achsen richtig zugeordnet.
    Allerdings sieht man aus dem Bild auch, dass die Sequenzen zwar mit der Zeit größer werden, allerdings nie wirklich gleichmäßig sind.
    Sprich manchmal werden 3-4 oder mehr hintereinander liegende gesendete Nachrichten gelesen, manchmal aber auch 10 ausgelassen.
    Weiß jemand woran das liegen könnte bzw. wie man die Schleife so gestaltet, sodass jede zweite Nachricht gelesen wird?

    hal2000 schrieb:

    OffTopic: Crossposting in verschiedenen Foren ist nicht gerade nett.

    Da hast du natürlich Recht. Aber es war eine Woche lang nichts los hier. (nicht das ich das irgendjemandem übel nehme oder so)
    Mein Problem ist ja sehr speziell und für die meisten nicht wirklich relevant.
    Daher möchte ich mich bei allen nochmal bedanken, vor allem bei @hal2000 für die wirklich gute Hilfe!! Danke :thumbsup:
    Bilder
    • bild_der_Sensorwerte.JPG

      125,86 kB, 686×710, 18 mal angesehen

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „chris_2091“ ()

    chris_2091 schrieb:

    Weiß jemand woran das liegen könnte bzw. wie man die Schleife so gestaltet, sodass jede zweite Nachricht gelesen wird?

    Das liegt vermutlich an der Überlastung des Sensors (zu oft in zu kurzer Zeit abgefragt). Verlangsame testweise die Abfrageschleife (Thread.Sleep, siehe oben). "Jede zweite Nachricht" liest du, indem du alle Nachrichten liest und bei der Verarbeitung jede zweite weglässt.

    Wenn du die Lust an Interop noch nicht verloren hast, kannst du auch die asynchrone Variante verwenden. Dabei ruft die DLL ein vorher definiertes Callback auf, sobald neue Daten vorhanden sind. Die Daten werden passenderweise gleich mitgeliefert. Das dürfte die Performance spürbar erhöhen und die Last auf dem Bus verringern, ist aber recht aufwendig.

    chris_2091 schrieb:

    Aber es war eine Woche lang nichts los hier.

    Wie gesagt - die Forensoftware zeigt Editierungen nicht als "neuen Inhalt" an. In diesem Fall einfach einen neuen Post drunter setzen mit "Edit-Push" als Inhalt (oder den gesamten Inhalt in den neuen Post schreiben), sonst sieht das niemand.
    Gruß
    hal2000
    Danke dir !!

    hal2000 schrieb:

    Wenn du die Lust an Interop noch nicht verloren hast, kannst du auch die asynchrone Variante verwenden. Dabei ruft die DLL ein vorher definiertes Callback auf, sobald neue Daten vorhanden sind.

    Ich schaue mir das mal an.

    Ich habe vor dem Schleifenende einfach das Sytem für 20ms pausieren lassen, da hat er ziemlich gleichmäßig jede zweite Nachricht gelesen.
    Aber deine Idee @hal2000 jede zweite Nachricht nur zu verarbeiten klingt gut. Ich probiere das aus. Wichtig ist für mich, dass keine allzu großen Sprünge entstehen (so hat der mal 20 Nachrichten "überlesen") da das die Daten unbrauchbar macht. Wir wollen nämlich damit Gesten erkennen, da wäre sowas fatal.

    hal2000 schrieb:

    Wie gesagt - die Forensoftware zeigt Editierungen nicht als "neuen Inhalt" an.

    gut jetzt weiß ich Bescheid!