C-Code nach Python portieren

Python in C/C++ embedden, C-Module, ctypes, Cython, SWIG, SIP etc sind hier richtig.
deets

Der erste ist genau wie erwartet.

Das zweite sieht mir noch nicht mal nach gueltigem python aus?!? cast ist eine *Funktion* in Python, kein Operator wie in C. Hast du das mal versucht?
deets

Ok, jetzt habe ich deinen Post erst richtig verstanden. Offensichtlich ist POINTER(foo) ein callable.

Wie dem auch sei, du musst die Funktion cast benutzen, sowas wie

cast(wert, POINTER(typ))


Kann auch sein, dass die Argumente umgedreht sind, bitte mal die Doku checken.
Torsten2000
User
Beiträge: 40
Registriert: Montag 27. Dezember 2010, 17:26

Wie caste ich denn auf POINTER(c_byte)?

ich hatte das jetzt mal so probiert... ist sehr wahrscheinlich totaler quatsch
POINTER(c_byte)( )

ich habe folgende typen gefunden
c_char_p char * (NUL terminated) string or None
c_wchar_p wchar_t * (NUL terminated) unicode or None
c_void_p void * int/long or None

c_byte_p ist leider nicht dabei...

casten auf c_char_p, c_wchar_p und c_void_p hat leider kein erfolg gebracht :?
BlackJack

@Torsten2000: Der allererste Aufruf den Du gezeigt hast, der sollte so auch funktionieren. `ctypes` nimmt es an der Stelle ähnlich "ungenau" wie C und übergibt bei einem Array nicht das Array selbst, sondern einen Pointer darauf. Das passt schon.

Kann es sein, dass die Signatur einfach nicht stimmt und die Funktion in der DLL andere/weniger Argumente entgegen nimmt?

Oh und natürlich das Offensichtliche: Ist das überhaupt eine DLL, die die Windows-Aufrufkonvention verwendet? Kann es sein, dass Du die nicht als windll sondern als cdll laden musst!?
Torsten2000
User
Beiträge: 40
Registriert: Montag 27. Dezember 2010, 17:26

Vielen Dank, dass ihr euch so viel Zeit für mich nehmt...

Also im Beispielprogramm steht der Aufruf so:

Code: Alles auswählen

unmangle(m_lpbWave, m_iCurSize, 0, m_TestBuf, sizeof(m_TestBuf), ghmTbl[giHwMode].iP1, ghmTbl[giHwMode].iP2, ghmTbl[giHwMode].iP3);
also nehme ich an, das die Anzahl der Argumente passt.

Die DLL habe ich von dem gleichen Hersteller. Daher war ich davon ausgegangen, dass das auch eine WinDLL ist.
Ich habe aber mal beim laden auch CDLL ausprobiert.

Code: Alles auswählen

#LAWaveExt_dll = windll.LoadLibrary("LAWaveExt")
LAWaveExt_dll = cdll.LoadLibrary("LAWaveExt")
Was leider kein Unterschied von der Fehlermeldung gemacht hat.
_unmangle( Wave, len(Wave), Channel, Wave_of_channel, len(Wave_of_channel), P1, P2, P3)
ArgumentError: argument 1: <type 'exceptions.TypeError'>: expected LP_c_byte instance instead of str
Torsten2000
User
Beiträge: 40
Registriert: Montag 27. Dezember 2010, 17:26

vielleicht ist das noch hilfreich.

in der lawaveext.h steht

Code: Alles auswählen

extern "C" int __declspec(dllexport) unmangle(BYTE *lpbWave, int sizeofWave, int iChan, BYTE* lpChan, int sizeofChan, int ip1, int ip2, int ip3);
deets

BlackJack hat geschrieben:@Torsten2000: Der allererste Aufruf den Du gezeigt hast, der sollte so auch funktionieren. `ctypes` nimmt es an der Stelle ähnlich "ungenau" wie C und übergibt bei einem Array nicht das Array selbst, sondern einen Pointer darauf. Das passt schon.
Haette ich das mal frueher gewusst... ich hab' immer schoen brav gepointert, und *dann* noch casten muessen.

You live, you learn.
deets

Torsten2000 hat geschrieben:
_unmangle( Wave, len(Wave), Channel, Wave_of_channel, len(Wave_of_channel), P1, P2, P3)
ArgumentError: argument 1: <type 'exceptions.TypeError'>: expected LP_c_byte instance instead of str
Aber das ist doch ein komplett anderer Fehler - das sieht so aus, als ob du keinen Array-Pointer uebergibst, sondern einen Python-string.
Torsten2000
User
Beiträge: 40
Registriert: Montag 27. Dezember 2010, 17:26

Oh je...
ich habe wieder ein Problem bekommen...

und zwar funktionierte das messen schon recht gut.
Ich muss jetzt allerding ein Gerät ansteuern, was nur mit IronPython geht.

Blöderweise bringt der mir eine Fehlermeldung in IronPython
in start_capturing _ctypes.ArgumentError: expected c_long, got c_long_Array_16
Damit funktioniert das Messen mit dem Logikanalysator nicht mehr!!! :(

Zur Erinnerung:

Code: Alles auswählen

TriggerContinue = (c_int * 16)()
TriggerData = (c_byte * (16 * 64))()

_capture = larun_dll.ulaCapture
_capture.argtypes = [POINTER(Trigger), POINTER(c_int), POINTER(c_byte)]
_capture.restype = c_bool

Code: Alles auswählen

def start_capturing():
    return _capture(trigger, TriggerContinue, TriggerData)
Was mache ich denn jetzt?
Wie löst man das Problem am besten?

Vielen Dank für eure Hilfe!
Grüße Torsten
BlackJack

Hilft folgende Änderung? (`byref()` ist aus `ctypes`)

Code: Alles auswählen

def start_capturing():
    return _capture(trigger, byref(TriggerContinue), byref(TriggerData))
Torsten2000
User
Beiträge: 40
Registriert: Montag 27. Dezember 2010, 17:26

Hallo BlackJack,

vielen Dank nochmal für eine schnelle Antwort!

leider hat das nicht geholfen.

Fehlermeldung:
in start_capturin _ctypes.ArgumentError: expected LP_c_long, got NativeArgument
Viele Grüße
Torsten
Torsten2000
User
Beiträge: 40
Registriert: Montag 27. Dezember 2010, 17:26

Mmmm.... hat noch jemand eine Idee, woran das liegen könnte, dass ich in IronPython den Logikanalysator nicht ansteuern kann? schon doof, das das nicht abwärtskompatibel ist...

Ich könnte evt. ein Umweg machen: aus dem Python-Skript ein IronSkrift über die Shell aufrufen... aber das ist wahrscheinlich sehr langsam und nicht sehr elegant...

Danke für eure Hilfe

Grüße
Torsten
Torsten2000
User
Beiträge: 40
Registriert: Montag 27. Dezember 2010, 17:26

Hallo,
ich habe nochmal die ctypes-Anleitung durchgearbeitet und habe leider immer noch das Problem, dass in IronPython die Fehlermeldung kommt (in Python funktioniert es).
in start_capturing _ctypes.ArgumentError: expected c_long, got c_long_Array_16
ich verstehe das nicht wirklich und bräuchte da dringend Hilfe (Die Abgabe von der Diplomarbeit kommt immer nächer).

Danke schon mal für eure Hilfe.

Grüße
Torsten
deets

Die Fehlermeldung ist doch recht klar. Und ich habe dir auch schon vor Wochen genau dazu was bezueglich casting gesagt.
BlackJack

@Torsten2000: Ansonsten ist das Thema IronPython's `ctypes`-Implementierung und Abweichungen von CPython's `ctype` hier vielleicht etwas zu speziell. Schau mal ob es für beides nicht auch Mailinglisten gibt, wo die Entwickler mitlesen oder zumindest Leute die auch die Implementierung kennen.
Torsten2000
User
Beiträge: 40
Registriert: Montag 27. Dezember 2010, 17:26

Hallo BlackJach,

danke für deine Antwort.

Ich rufe jetzt mit

Code: Alles auswählen

os.popen('set_ScaleRT_blocking_bit.ipy').read()
ein externes IronPython-Script auf.

es funktioniert zwar aber ist sehr langsam, da er sich immer wieder neu verbinden muss.

man man zwei Python-Scripte gleichzeitig laufen lassen, die sich Variablen teilen?

Damit könnte man evtl. das auch beschleunigen
Torsten2000
User
Beiträge: 40
Registriert: Montag 27. Dezember 2010, 17:26

Sagt mal ....

was mir gerade aufgefallen ist...

Meine Read-Funktion ist der totaler blödsinn oder?

Code: Alles auswählen

def read_data_from_file(filename):
   import os
   global Wave

   f=open(filename, 'rb')
   print os.path.getsize(filename)
   Wave = (c_byte * ( os.path.getsize(filename) ))()

   print 'Lese Daten von der Datei "' + filename + '" ...',
   Wave = f.read()
   f.close
   print '   OK'
   print
Das ist ja dann nicht in das Byte-Array reingeschrieben...
Der erstellt mir ja eine neue Variable.
muss ich da auch mit dem strukt paket arbeiten?
oder wie machte ich das?
Torsten2000
User
Beiträge: 40
Registriert: Montag 27. Dezember 2010, 17:26

Nochmal auf das Problem zurück zu kommen...

Zur Erinnerung:

Also - in der DLL ist eine Funktion

Code: Alles auswählen

unmangle(BYTE *lpbWave, int sizeofWave, int iChan, BYTE* lpChan, int sizeofChan, int ip1, int ip2, int ip3)
und so habe ich das eingebunden

Code: Alles auswählen

import ctypes
LAWaveExt_dll = windll.LoadLibrary("LAWaveExt")
_unmangle = LAWaveExt_dll.unmangle
_unmangle.argtypes = [POINTER(c_byte), c_int, c_int, POINTER(c_byte), c_int, c_int, c_int, c_int]
_unmangle.restype = c_int


def unmangle():
   Channel = 0

   Wave =             (c_byte * ( 80 ))()
   Wave_of_channel =  (c_byte * ( 80 ))()
   _unmangle( Wave, sizeof(Wave), Channel, Wave_of_channel,  sizeof(Wave_of_channel), P1, P2, P3)
Da bringt er folgende Fehlermeldung:
_unmangle( Wave, sizeof(Wave), Channel, Wave_of_channel, sizeof(Wave_of_channel), P1, P2, P3)
ValueError: Procedure probably called with too many arguments (32 bytes in excess)
Muss ich bei der Übergabe von den Parameter die "pack"-Funktion aus Struct benutzen oder macht der das automatisch...
weil ich bei der Deklaration ja die Größe angegeben haben...

Viele Grüße
Torsten
BlackJack

@Torsten2000: Du hast da doch gar kein ``struct``/`ctypes.Structure`.
Antworten