Problem mit Daten in ctypes

Python in C/C++ embedden, C-Module, ctypes, Cython, SWIG, SIP etc sind hier richtig.
manlud80
User
Beiträge: 11
Registriert: Mittwoch 13. Januar 2016, 12:50

Problem mit Daten in ctypes

Beitragvon manlud80 » Mittwoch 13. Januar 2016, 12:56

Hallo zusammen,
ich habe ein Problem, Daten über eine Funktion einer DLL abzurufen. Ich will von einem RFID-Reader Daten auslesen, dazu habe ich mit einer DLL mit dem Befehl

Code: Alles auswählen

b = WinDLL("C:\\...\\nameofdll.dll")

verbunden.
Mit der Funktion Inventory_G2 kann man nun die RFID-Daten abrufen. Mein Befehl sieht so aus:

Code: Alles auswählen

b.Inventory_G2(c_ubyte(int("ff", 16)), c_ubyte(0), c_ubyte(0), c_ubyte(0), (c_ubyte*1000)(), None, None, c_long(int("33f0000", 16)))

Die Fehlermeldung dazu lautet:
WindowsError: exception: access violation reading 0x00000030

Vom Hersteller wurde Quellcode in C# bereitgestellt, der die Funktion wie folgt erfolgreich verwendet:

Code: Alles auswählen

byte AdrTID = 0;
byte LenTID = 0;
byte TIDFlag = 0;
CardNum=0;
Totallen = 0;
byte[] EPC=new byte[5000];
fComAdr = 0xFF;
fCmdRet = StaticClassReaderB.Inventory_G2(ref fComAdr,AdrTID,LenTID,TIDFlag, EPC, ref Totallen, ref CardNum, frmcomportindex);


Kann mir jemand helfen? Wie rufe ich die Funktion korrekt in Python auf?
Sirius3
User
Beiträge: 7043
Registriert: Sonntag 21. Oktober 2012, 17:20

Re: Problem mit Daten in ctypes

Beitragvon Sirius3 » Mittwoch 13. Januar 2016, 13:15

@manlud80: in der Signatur der Funktion gibt es mehrere Parameter, die eine Referenz (Pointer) auf die Variablen erwarten und nicht ihren Wert.
manlud80
User
Beiträge: 11
Registriert: Mittwoch 13. Januar 2016, 12:50

Re: Problem mit Daten in ctypes

Beitragvon manlud80 » Mittwoch 13. Januar 2016, 13:30

Super, das hat schonmal geholfen... Mit

Code: Alles auswählen

b.Inventory_G2(byref(c_ubyte(int("ff", 16))), c_ubyte(0), c_ubyte(0), c_ubyte(0), test, None, byref(c_ubyte(0)), c_long(int("33f0000", 16)))


bekomme ich schonmal "nur noch" die Fehlermeldung "55" zurück, aber noch keine Daten.
Kann mir jemand sagen, was ich noch falsch mache?
Vielen Dank schonmal Sirius3.
BlackJack

Re: Problem mit Daten in ctypes

Beitragvon BlackJack » Mittwoch 13. Januar 2016, 14:24

@manlud80: Wo sollten die Daten denn stehen? Und darf man bei `Totallen` aus dem C#-Beispiel einen NULL-Pointer angeben? Ich weiss auch nicht ob es so gut ist bei `byref()` direkt ein erzeugtes `ctypes`-Objekt zu übergeben weil `byref()` in der Dokumentation als ”leichtgewichtige” Alternative zu `pointer()` speziell für Funktionsaufrufe beschrieben wird. Es kann also gut sein dass diese Funktion nicht dafür sorgt das es eine Referenz auf das Argument gibt solange der Rückgabewert der Funktion verwendet wird und man sich so Pointer auf nicht (mehr) existierende Objekte/Speicherbereiche schafft. Ich würde an der Stelle das C#-Beispiel ähnlicher Nachbauen und vor dem Aufruf die Werte an Namen binden die da als Pointer übergeben werden.

Dieses `int('...', 16)` für die Hexadezimalzahlen ist übrigens unnötig umständlich. Python versteht auch die Notation für Hex-Literale wie bei der C-Sprachfamilie, also beispielsweise einfach ``0xff`` statt ``int('ff', 16)``.
manlud80
User
Beiträge: 11
Registriert: Mittwoch 13. Januar 2016, 12:50

Re: Problem mit Daten in ctypes

Beitragvon manlud80 » Mittwoch 13. Januar 2016, 15:49

Vielen Dank dafür.
Die Daten müssen in "test" stehen, wobei

Code: Alles auswählen

test=(c_ubyte*5000)()

ist.
Den Nullpointer habe ich jetzt durch ein c_ubyte(0) ersetzt und die byref durch pointer ersetzt. Leider immer noch der gleiche Rückgabewert ("55"). Kann es sein, dass meine test-Variable falsch ist?
Sirius3
User
Beiträge: 7043
Registriert: Sonntag 21. Oktober 2012, 17:20

Re: Problem mit Daten in ctypes

Beitragvon Sirius3 » Mittwoch 13. Januar 2016, 16:21

@manlud80: was heißt denn 55? Es muß doch irgendwo eine Fehlermeldungsbeschreibung geben.
manlud80
User
Beiträge: 11
Registriert: Mittwoch 13. Januar 2016, 12:50

Re: Problem mit Daten in ctypes

Beitragvon manlud80 » Mittwoch 13. Januar 2016, 16:33

Nein, leider nicht. In der DLL-Beschreibung steht, dass bei erfolgreich ausgeführtem BEfehl die 0 zurückgegeben wird.
BlackJack

Re: Problem mit Daten in ctypes

Beitragvon BlackJack » Mittwoch 13. Januar 2016, 16:42

@manlud80: Was hast Du denn da genau? Welches Gerät? Wie heisst die DLL? Woher hast Du die Dokumentation?

Wenn ich nach RFID und dem Funktionsnamen im Netz suche, finde ich beispielsweise dieses PDF: http://www.rfidshop.com.hk/datasheet/UH ... 20v1.2.pdf

Da steht bei Fehlercode 55 (0x37) „Invalid Handle“, was mir auch sinnvoll erscheint, denn die 0x33f0000 fällt in Deinem Code ja irgendwie vom Himmel herab. Wo hast Du den Wert her? In der Dokumentation stehen die Funktionen mit denen man den tatsächlichen, dynamischen Wert bekommt.

Edit: Auch wenn das bei Windows nicht zwingend nötig ist, würde ich mir erst einmal die Funktionen aus der DLL holen und die Signaturen definieren. Dann sehen die Aufrufe etwas weniger überfrachtet aus und sind auch sicherer. Ausserdem kann man den Rückgabewert dann auch gleich in eine Ausnahme umwandeln lassen wenn etwas nicht geklappt hat und kann ”pythonischeren” Code schreiben. Eventuell auch das Handle in ein Objekt kapseln.
manlud80
User
Beiträge: 11
Registriert: Mittwoch 13. Januar 2016, 12:50

Re: Problem mit Daten in ctypes

Beitragvon manlud80 » Mittwoch 13. Januar 2016, 17:03

Ja, ich habe so ein ähnliches Gerät, die Inventory-Funktion ist nahezu identisch.

Ups, die Fehlercodes hatte ich bisher noch nicht gesehen. Bisher kam ich auch noch nie bis dort.

Das handle habe ich von der WinDLL b(siehe mein erster Post):

<WinDLL 'C:\...\nameofdll.dll', handle 33f0000 at 2d15fd0>

Die Funktion AutoOpenComPort() soll eigentlich einen gültigen handle übergeben, ich bekomme aber nur eine 0 für "erfolgreich verbunden".
BlackJack

Re: Problem mit Daten in ctypes

Beitragvon BlackJack » Mittwoch 13. Januar 2016, 17:15

@manlud80: Das ist das Handle für die DLL, Du brauchst eines für einen geöffneten COM-Port das mit einer der beiden Open-Funktionen zu bekommen ist. Der Rückgabewert dieser Funktionen ist ja nicht das einzige Ergebnis. Das scheint immer eine Art Fehlercode zu sein. Alle anderen Werte werden über die Zeiger zurückgegeben die als Argumente übergeben werden.
manlud80
User
Beiträge: 11
Registriert: Mittwoch 13. Januar 2016, 12:50

Re: Problem mit Daten in ctypes

Beitragvon manlud80 » Mittwoch 13. Januar 2016, 17:34

Ok, danke. Kannst du mir sagen, wie ich auf diese Werte zugreifen kann?
BlackJack

Re: Problem mit Daten in ctypes

Beitragvon BlackJack » Mittwoch 13. Januar 2016, 19:03

@manlud80: Du musst die Werte halt an Namen binden und beim Aufruf eine Referenz auf den Wert übergeben. Die C-Funktion ändert dann den Wert die von dem jeweiligen `ctypes`-Objekt gekapselt wird.
Dav1d
User
Beiträge: 1437
Registriert: Donnerstag 30. Juli 2009, 12:03
Kontaktdaten:

Re: Problem mit Daten in ctypes

Beitragvon Dav1d » Mittwoch 13. Januar 2016, 21:26

Nicht direkt eine Lösung für dein Problem (und auch gerade unrelated), empfehle dir aber cffi anzuschauen. Effizienter als ctypes und um seeeehr viel einfacher zu handhaben.
the more they change the more they stay the same
BlackJack

Re: Problem mit Daten in ctypes

Beitragvon BlackJack » Donnerstag 14. Januar 2016, 00:30

Vollkommen ungetestet:
  1. from ctypes import byref, c_long, c_uint8, POINTER, WinDLL
  2.  
  3. READER_DLL = WinDLL('nameofdll.dll')
  4. (
  5.     BAUD_9600,
  6.     BAUD_19200,
  7.     BAUD_38400,
  8.     _,
  9.     BAUD_56000,
  10.     BAUD_57600,
  11.     BAUD_115200
  12. ) = xrange(7)
  13.  
  14.  
  15. class ReaderException(Exception):
  16.  
  17.     def __init__(self, error_code):
  18.         Exception.__init__(self, 'Error code 0x{0:x}'.format(error_code))
  19.         self.error_code = error_code
  20.  
  21.  
  22. def _error_check(result, _func, _arguments):
  23.     if result:
  24.         raise ReaderException(result)
  25.     return result
  26.  
  27.  
  28. _auto_open_com_port = READER_DLL.AutoOpenComPort
  29. _auto_open_com_port.argtypes = (
  30.     POINTER(c_long), POINTER(c_uint8), POINTER(c_uint8), POINTER(c_long)
  31. )
  32. _auto_open_com_port.restype = c_long
  33. _auto_open_com_port.errcheck = _error_check
  34.  
  35.  
  36. def auto_open_com_port(port=0, com_address=0xff, baud=BAUD_57600):
  37.     port = c_long(port)
  38.     com_address = c_uint8(com_address)
  39.     baud = c_uint8(baud)
  40.     handle = c_long()
  41.     _auto_open_com_port(
  42.         byref(port), byref(com_address), byref(baud), byref(handle)
  43.     )
  44.     return port.value, com_address.value, baud.value, handle

Wobei man wie schon gesagt, dann am besten die entsprechenden Werte die immer wieder gebraucht werden in Objekten zusammenfasst statt die Funktionen tatsächlich als Funktionen 1:1 abzubilden.
manlud80
User
Beiträge: 11
Registriert: Mittwoch 13. Januar 2016, 12:50

Re: Problem mit Daten in ctypes

Beitragvon manlud80 » Freitag 15. Januar 2016, 11:35

Hallo Blackjack,

das hat ja schonmal super funktioniert mit dem Comport. Vielen Dank.

Wenn du mir jetzt noch helfen könntest, die Inventory_G2 erfolgreich auszuführen, dann wäre ich restlos glücklich :-)

Der folgende Code spuckt den Fehler 0x01 aus (Return before Inventory finished):
  1. from ctypes import byref, c_long, c_uint8, POINTER, WinDLL, c_ubyte, cast
  2.  
  3. READER_DLL = WinDLL('nameofdll.dll')
  4. (
  5.     BAUD_9600,
  6.     BAUD_19200,
  7.     BAUD_38400,
  8.     _,
  9.     BAUD_56000,
  10.     BAUD_57600,
  11.     BAUD_115200
  12. ) = xrange(7)
  13.  
  14.  
  15. class ReaderException(Exception):
  16.  
  17.     def __init__(self, error_code):
  18.         Exception.__init__(self, 'Error code 0x{0:x}'.format(error_code))
  19.         self.error_code = error_code
  20.  
  21.  
  22. def _error_check(result, _func, _arguments):
  23.     if result:
  24.         raise ReaderException(result)
  25.     return result
  26.  
  27.  
  28. _auto_open_com_port = READER_DLL.AutoOpenComPort
  29. _auto_open_com_port.argtypes = (
  30.     POINTER(c_long), POINTER(c_uint8), POINTER(c_uint8), POINTER(c_long)
  31. )
  32. _auto_open_com_port.restype = c_long
  33. _auto_open_com_port.errcheck = _error_check
  34.  
  35.  
  36. _Inventory_G2 = READER_DLL.Inventory_G2
  37. _Inventory_G2.argtypes = (
  38.     POINTER(c_ubyte), c_ubyte, c_ubyte, c_ubyte, POINTER(c_ubyte), POINTER(c_long), POINTER(c_long), c_long
  39. )
  40. _Inventory_G2.restype = c_long
  41. _Inventory_G2.errcheck = _error_check
  42.  
  43.  
  44. def auto_open_com_port(port=8, com_address=0xff, baud=BAUD_57600):
  45.     port = c_long(port)
  46.     com_address = c_uint8(com_address)
  47.     baud = c_uint8(baud)
  48.     handle = c_long()
  49.     _auto_open_com_port(
  50.         byref(port), byref(com_address), byref(baud), byref(handle)
  51.     )
  52.     return port, com_address, baud, handle
  53.  
  54. def Inventory_G2(com_address, handle):
  55.     AdrTID=c_ubyte(0)
  56.     LenTID=c_ubyte(0)
  57.     TIDFlag=c_ubyte(0)
  58.     EPClenandEPC=(c_ubyte*5000)()
  59.     Totallen=c_long(0)
  60.     CardNum=c_long(0)
  61.     _Inventory_G2(
  62.         byref(com_address), AdrTID, LenTID, TIDFlag, cast(EPClenandEPC, POINTER(c_ubyte)), byref(Totallen), byref(CardNum), handle
  63.     )
  64.     print EPClenandEPC
  65.     return com_address, AdrTID, LenTID, TIDFlag, EPClenandEPC, Totallen, CardNum, handle
  66.  
  67. [port, com_address, baud, handle]=auto_open_com_port()
  68. [com_address, AdrTID, LenTID, TIDFlag, EPClenandEPC, Totallen, CardNum, handle] = Inventory_G2(com_address, handle)


Kannst du nochmal helfen?

Wer ist online?

Mitglieder in diesem Forum: Yahoo [Bot]