C-Code nach Python portieren

Python in C/C++ embedden, C-Module, ctypes, Cython, SWIG, SIP etc sind hier richtig.
Torsten2000
User
Beiträge: 40
Registriert: Montag 27. Dezember 2010, 17:26

Hallo,
so jetzt habe ich mich auch mal angemeldet. Hab sonst immer die nötigen Antworten im Forum gefunden, so dass ich selber nie einen Eintrag schreiben musste. Leider habe ich diesmal nichts gefunden. Vorab, ich bin in Python totaler Anfänger und in C kann ich wohl nur die Grundlagen.

So also zu meinem Problem:
ich soll ein Logikanalysator mittels DLL ansprechen.
Beispielprogramme in C++, DLL und Manual findet man unter
http://www.acute.com.tw/Software/dll_sc/la_vc.zip
Einige Sachen wie Initalisieren habe ich bereits zum laufen gebracht. Nur das "Starte Messung" und "Empfange Daten" habe ich noch nicht zum laufen gebracht.
Das Problem, was ich habe sind die Pointer, Strukturen und Arrays (Denke ich).

Die DLL habe ich wie folgt eingebunden

Code: Alles auswählen

import ctypes
windll = ctypes.windll.LoadLibrary("LaRun.dll")
Es gibt folgende Funktionen (C-Code)

Code: Alles auswählen

#Habe ich zum laufen gebracht:
#BOOL ulaInit();
#BOOL ulaShutdown();
#BOOL ulaThreshold( int iPod, int iMilliVolt );
#INT ulaGetHwInfo( UINT nIndex );
#BOOL ulaSetHwInfo( UINT nIndex, int iValue );


#läuft noch nicht
#BOOL ulaGetModelName( LPSTR szModel, int iSize );
#BOOL ulaCapture( LPTRIG lptr, int *lpi, LPBYTE lpb );
#BOOL ulaRead( LPBYTE lpb, int iFlag );
habe ich so übersetzt:

Code: Alles auswählen

def ulaInit():
   return windll.ulaInit()

...

#bei den weiß ich nicht ob ich das richtig gemacht habe, wegen Pointern etc.

#Start capturing signals data.
def ulaCapture(lptr, lpi, lpb):
   return windll.ulaCapture(lptr, lpi, lpb)

#Read back the LA captured data.
def ulaRead(lpb, iFlag):
   return windll.ulaRead(lpb, iFlag)
die letzen beiden sind meine Problemfunktionen
Bei der ulaCapture muss man ein Struct übergeben, was ich wie folgt gelöst habe
(ob das richtig ist?)

C-Code

Code: Alles auswählen

typedef struct _TRIG
{
    int         iFlag;          
    int         iCh;            

...
    int         *lpiCont;       
    BYTE        *lpbTrigData;
} TRIG, FAR *LPTRIG;

Was bedeutet eigentlich bei _TRIG der Unterstrich?
habe ich so gelöst:

Code: Alles auswählen

class TRIG:
   pass

m_tr = TRIG()

#Variable Wert zuweisen, damit die existiert
m_tr.iFlag =  2
...
So den anderen Quellcode kopiere ich erst mal nicht.
ist das denn bis dahin richtig?
Mit den Struct und den Pointern?
Gibt es eigentlich eine übersetzung für #define?
Wie ist das mit den Arrays?

Als nächstes muss ich die LaStream.cpp und die LaStream.h übersetzen, was ich noch nicht so genau weiß, wie ich das machen soll.
Aber erst mal so weit.

Könnt Ihr mir da vielleicht ein Tipp geben?
hilfen mir eigentlich die Befehle
# Extension
# Cython
?

Hier dochnochmal was - Aufruf der Funktionen in C:

Code: Alles auswählen

	int		m_iTrCont[16];               // For Trigger Parameter
	BYTE		m_bTrData[64*16];         // For Trigger Parameter
	TRIG		m_tr;	                      // Trigger Structure


	ulaCapture( &m_tr, m_iTrCont, m_bTrData );

	ulaRead( m_lpbWave, -1 );
Wie übersetzte ich das?

Ich hoffe, das ist jetzt nicht zu wirr, was ich geschrieben haben und man versteht es trotzdem.

Vielen Dank schon mal für eure Hilfe
BlackJack

@Torsten2000: Ich würde die Funktionen in Python an Namen binden und die Argument- und Rückgabetypen darauf dann ordentlich mit `argtypes`- und `restype`-Attributen "deklarieren". So wie es jetzt da steht wären auch die ``def``\s unnötig. Ich würde bei den Namen auch den Präfix weglassen. Dass da anscheinend überall `ula` davor steht, ist ja nur weil C keine Namensräume kennt. Das ist in Python ja $GOTT sei Dank nicht der Fall.

Und man muss IMHO C und Python gut beherrschen, wenn man mit `ctypes` arbeitet, damit man weiss was man da tut. Da verlässt man nämlich die schöne heile Welt der Hochsprache wo es saubere Ausnahmen und Tracebacks gibt, wenn man etwas falsch macht und betritt das Land der unbemerkten Datenmanipulation und der harten Programmabstürze.

Der Unterstrich bei `_TRIG` bedeutet von der Sprache her nichts, das ist einfach ein Zeichen des Namens von der Struktur. Eine feste Konvention gibt es bei C nicht, aber das wird in dem Projekt wohl die Konvention sein um der Struktur einen Namen zu geben, die unterschiedlich zu dem Alias ist, den man ihr über das ``typedef`` verpasst, damit man beide auseinanderhalten kann. Ich tendiere dazu in solchen Fällen den gleichen Namen einfach beide Male zu verwenden. Und den für die Struktur auch überhaupt nur anzugeben, wenn er innerhalb der Struktur auch tatsächlich verwendet wird. Nach der Deklaration steht ja der Alias zur Verfügung.

Das mit der Klasse funktioniert so nicht, denn `ctypes` muss ja alle Felder der Struktur inklusive ihrer Typen kennen, um daraus einen Speicherbereich erzeugen und befüllen zu können, der so aussieht, wie ihn eine C-Funktion erwartet. Dazu muss man eine Unterklasse von `ctypes.Structure` erstellen und die Attribute entsprechend der Dokumentation "deklarieren".

Ich würde die Funktionen in `cpython` "deklarieren" -- ohne gemeinsamen Präfix, der vielleicht ein passender Modulname wäre -- und dann auch erst einmal überlegen wie eine "pythonische" API dazu aussehen kann. Wenn man C 1:1 in Python umsetzt hat man ja nichts gewonnen -- da kann man auch gleich bei C bleiben.

Bei dem letzten C-Beispiel musst Du halt mit `ctypes` die passenden Typen erstellen, aus denen dann Objekte die "Exemplare" von diesen Typen repräsentieren und damit dann entsprechend die Objekte aufrufen, die die C-Funktionen repräsentieren.

Also zum Beispiel für `m_iTrCont` einen Typ der ein 16-elementiges ``int``-Array darstellt aufrufen und an einen Namen binden. Wenn man einfallslos ist, an den Namen `m_iTrCont` -- wenn man lesbare Programme schreiben möchte, dann bitte etwas das verständlicher ist. Wenn man das nicht macht, sollte man IMHO ebenfalls besser die Finger von Python lassen.
BlackJack

@Torsten2000: Ich habe mal nur Aufgrund der knappen API-Beschreibung was geschrieben: http://paste.pocoo.org/show/310726/

Völlig ungetestet, da mir ja die Hardware und auch das verwendete Betriebssystem abgeht. :-)

Und auch ohne tieferes Verständnis dafür was die Hardware macht und wie man die API benutzt. Das könnte also alles von der Benutzbarkeit her suboptimal sein.

Der `Trigger`-Klasse könnte man noch eine Menge `property()`\s verpassen. Zum Beispiel um die einzelnen Flags vom `flag`-Feld mit Namen ansprechen zu können, oder die 64-Bit-Frequenz als *einen* Wert. In der `__init__()` habe ich nur die Werte vorbelegt, wo in der Doku unmissverständlich stand was dort als Wert hinein muss.

Den `Analyzer` kann man mit der ``with``-Anweisung verwenden, da der "shutdown" ziemlich wichtig ist.

Beim `read()` habe ich ein wenig geraten, ob man das so umsetzen würde.

Und für die Arrays `self.relations` und `self.buffer` gibt es keine spezielle API. Da fehlte mir wieder die Info was die bedeuten und wie man die verwendet. Die Konstanten dafür sind auf `Trigger` definiert.
Torsten2000
User
Beiträge: 40
Registriert: Montag 27. Dezember 2010, 17:26

Hallo Black Jack,

Vielen Dank für deine schnelle Antwort...
Da hast du ja wirklich keine Mühen gescheut...
Da werde ich sicherlich viel rausholen können...

Von der Struktur ist ja echt super...
mit schönen Namen, die ohne Anleitung auskommen versuche ich normalerweise auch zu Programmieren. Wollte erst mal das überhaupt zum laufen bringen, deswegen habe ich mich sehr an die C-Dateien angelehnt.
Da kann ich wohl noch eine Menge lernen...

Bis ich mich durch alle deine Infos durchgewurschtelt habe, wird das wohl noch einige Zeit dauern... aber ich werde wohl deine Hilfe nochmal in anspruch nehmen müssen.

Vielen Dank schon mal!!!

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

so da bin ich wieder...
Da habe ich jetzt leider einiges nicht so ganz verstanden...
@Torsten2000: Ich würde die Funktionen in Python an Namen binden und die Argument- und Rückgabetypen darauf dann ordentlich mit `argtypes`- und `restype`-Attributen "deklarieren".

Also damit meinst du sicherlich das wie in deinem Code-Beispiel steht.
Wofür ist denn da der Untersrich? ist das Teil des Namens? Muss ich dann die Funktion so aufrufen: "_init()"?
Präfix (Vorsilbe) ist wohl das ula bei ulaInit() oder?

Code: Alles auswählen

_init = larun_dll.ulaInit
_init.argtypes = []
_init.restype = c_bool
_init.errcheck = _errcheck
hab ich das richtig verstanden - ich sollte nicht mit ctypes arbeiten?
Du hast meine Zeile

Code: Alles auswählen

import ctypes
windll = ctypes.windll.LoadLibrary("LaRun.dll")
ausgetauscht mit

Code: Alles auswählen

from ctypes import (
    byref, c_bool, c_byte, c_char_p, c_int, c_uint, create_string_buffer,
    POINTER, Structure, windll
)
from ctypes.util import find_library
from time import sleep

larun_dll = windll.LoadLibrary(find_library("LaRun"))
letzte Zeile bringt er mir allerdings folgende Fehlermeldung (ach so ich arbeite mit Windows7)

Code: Alles auswählen

Traceback (most recent call last):
  File "C:\Users\Torsten Müller\Desktop\!!!Diplomarbeit-Torsten\Praxis\Python - LA auslesen\LA.py", line 88, in <module>
    larun_dll = windll.LoadLibrary(find_library("LaRun"))
  File "C:\Program Files\Python27\lib\ctypes\__init__.py", line 431, in LoadLibrary
    return self._dlltype(name)
  File "C:\Program Files\Python27\lib\ctypes\__init__.py", line 353, in __init__
    self._handle = _dlopen(self._name, mode)
TypeError: expected string or Unicode object, NoneType found
würde dein Code nicht die heile Welt der Hochsprache verlassen?

So erst mal so weit.
Ich versuche erstmal die Init und das shutdown wieder zum laufen zu bringen...
Vielen Dank für eure Hilfe...
lunar

Der Unterstrich ist Teil des Namens und dient per Konvention dazu, Namen als „privat“ zu kennzeichnen, und somit von der öffentlichen Schnittstelle eines Objekts auszuschließen. Der Unterstrich zeigt dem Benutzer eines Moduls oder einer Klasse, dass dieses Attribut nur internen Zwecken dient und von außen tunlichst nicht verwendet werden sollte. Das steht im Übrigen im Tutorial und sollte Dir nach dem Durcharbeiten desselben eigentlich bekannt sein.

Du hast BlackJack auch falsch verstanden, wenn Du aus seinen Ausführungen schließt, dass Du nicht mit ctypes arbeiten solltest. Im Gegenteil, ein anderer Weg als ctypes bleibt Dir ja nicht, zwangsläufig musst Du also mit ctypes arbeiten. Aber eben nur und ausschließlich im Modul, dass die C-Bibliothek einbindet. Dieses Modul sollte dann eine komfortable Schnittstelle anbieten, die den Konventionen und Idiomen von Python folgt, so dass der Benutzer dieses Modul im Idealfall gar nicht weiß, dass unter der Haube eine C-Bibliothek mit ctypes angesprochen wird. Genau das ist in BlackJacks Beispiel der Fall.

Zudem deklariert BlackJack auch entsprechende Typen für die Argumente und Rückgaben der C-Funktionen. Dadurch kann ctypes beim Aufruf der C-Funktionen Typprüfungen vornehmen, so dass auf Fehler frühzeitig und aussagekräftig in Form einer Ausnahme hingewiesen wird, statt dass sich der C-Code mit einem kommentarlosen Absturz verabschiedet. Zudem ermöglicht die Deklaration der Struktur als Python-Typ (in Form der von "Structure" abgeleiteten Klasse) den Zugriff auf die Attribute der entsprechenden Struktur.

Die Ausnahme erhältst Du, weil "find_library()" die Bibliothek nicht findet. Ich kenne mich mit Windows nicht gut genug aus, um Dich über den Unterschied zwischen der Verwendung von "find_library()" und dem direkten Laden der Bibliothek aufklären zu können. Hier sollte Dir die Dokumentation von ctypes weiterhelfen, die zu Lesen dringend anzuraten ist.
Torsten2000
User
Beiträge: 40
Registriert: Montag 27. Dezember 2010, 17:26

Ok vielen dank...

das hab ich wirklich falsch verstanden...

dann werde ich mal mich ran setzten und das ausprobieren

vielen dank

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

Hallo

ich habe mir jetzt das Tutorim durchgelesen und auch (die Klasse?) ctypes.
Vieles ist für mich jetzt klarer geworden.

leider hänge ich trotzdem schon wieder...
Ich weiß nicht, wie ich diese Structur am besten in Python übersetze

Code: Alles auswählen

struct HwMode
{
	int		iMode;
	I64		i64Freq;
	int		iMaxCh;
	int		iP1;
	int		iP2;
	int		iP3;
};

HwMode	ghmTbl[] = {   
					{    0, 4000000000i64, 36, 64, 36, 36 },		// 0
					{    1, 4000000000i64, 18, 64, 18, 18 },		// 1
					{    2, 4000000000i64,  9, 64,  9,  9 },		// 2
					{    3, 4000000000i64,  4, 64,  4,  4 },		// 3
					{  100, 2000000000i64, 36, 64, 36, 36 },		// 4
					{  200, 1600000000i64,  4, 64, 32,  4 },		// 5
					{  300,  800000000i64,  9, 64, 36,  9 },		// 6
					{  400,  400000000i64, 18, 64, 36, 18 },		// 7
					{  500,  200000000i64, 36, 64, 36, 36 },		// 8
					{  501,  200000000i64, 18, 64, 36, 18 },		// 9
					{  502,  200000000i64, 12, 64, 36, 12 },		// 10
					{  503,  200000000i64,  9, 64, 36,  9 },		// 11
					{  504,  200000000i64,  6, 64, 36,  6 },		// 12
					{  505,  200000000i64,  4, 64, 36,  4 },		// 13
					{  506,  200000000i64,  2, 64, 36,  2 },		// 14
					{  507,  200000000i64,  1, 64, 36,  1 },		// 15
					{  600,  200000000i64, 35, 64, 36, 36 },		// 16
					{  601,  200000000i64, 18, 64, 36, 18 },		// 17
					{  602,  200000000i64, 12, 64, 36, 12 },		// 18
					{  603,  200000000i64,  9, 64, 36,  9 },		// 19
					{  604,  200000000i64,  6, 64, 36,  6 },		// 20
					{  605,  200000000i64,  4, 64, 36,  4 },		// 21
					{  606,  200000000i64,  2, 64, 36,  2 },		// 22
					{  607,  200000000i64,  1, 64, 36,  1 }		// 23
ich kann eine Structure mit ctype anlegen:

Code: Alles auswählen

class hardware_mode(Structure):
    _fields_ = [
        ('Hardware_Mode', c_int),
        ('Frequency', c_int),
        ('Channels',  c_int),
        ('P1', c_int),
        ('P2', c_int),
        ('P3', c_int),
    ]
aber ich kann kein Array von der Structur anlegen. und wie fülle ich das dann?

ich könnte auch eine Python class definieren

Code: Alles auswählen

class hardware_mode:
    Hardware_Mode = 0
    Frequency = 0
    Channels = 0
    P1 = 0
    P2 = 0
    P3 = 0

Ich weiß, dass das nicht viel bringt, da ich auch eine leere Klasse anlegen könnte und die Varialben dann händisch initalisieren

Code: Alles auswählen

class hardware_mode:
    pass
hw = hardware_mode()
hw.Freqeuncy = 45
...
Aber dann habe ich wieder das Problem die Daten dort rein zubekommen (als array (indiziert)).

wie würdet ihr denn das am besten lösen?

Vielen Dank euch.
Auch für die letzten Antworten. So Hammergeile Anworten hätte ich mir in meinen kühnsten Träumen nicht erwartet!
Ich bin wirklich beeindruckt!
BlackJack

@Torsten2000: `ctypes` ist ein Modul. Und wie alles was man in Python an einen Namen binden kann ein Objekt.

Was genau brauchst Du denn da? Brauchst Du tatsächlich die C-Datenstruktur und ein Array mit solchen Einträgen, weil damit eine C-Funktion aufgerufen werden soll, oder einfach nur die Informationen als Python-Datentypen/-Strukturen?

Bei `hardware_mode` stimmt der Typ von `Frequency` eventuell nicht. Auf einem 32-Bit-System hätte das so keine 64 Bit.

Und bei der Variante mit der Python-Klasse definierst Du *Klassenattribute* was ja wahrscheinlich eher Attribute auf dem Exemplar sein sollen, denn du müsstest dann ja 24 Exemplare von der Klasse erzeugen.

Wenn es sich bei `HardwareMode` um einen reinen Datentyp handelt, der dazu noch unveränderlich ist, dann könnte man auch `collections.namedtuple` verwenden und die `_make()`-Methode auf die Elemente einer doppelt verschachtelten Liste mit der Wertetabelle anwenden.

Code: Alles auswählen

from collections import namedtuple

HardwareInfo = namedtuple('HardwareInfo', 'mode frequency channels p1 p2 p3')

HARDWARE_INFOS = map(HardwareInfo._make, [
    [    0, 4000000000, 36, 64, 36, 36 ],
    [    1, 4000000000, 18, 64, 18, 18 ],
    [    2, 4000000000,  9, 64,  9,  9 ],
    [    3, 4000000000,  4, 64,  4,  4 ],
    [  100, 2000000000, 36, 64, 36, 36 ],
    [  200, 1600000000,  4, 64, 32,  4 ],
    [  300,  800000000,  9, 64, 36,  9 ],
    [  400,  400000000, 18, 64, 36, 18 ],
    [  500,  200000000, 36, 64, 36, 36 ],
    [  501,  200000000, 18, 64, 36, 18 ],
    [  502,  200000000, 12, 64, 36, 12 ],
    [  503,  200000000,  9, 64, 36,  9 ],
    [  504,  200000000,  6, 64, 36,  6 ],
    [  505,  200000000,  4, 64, 36,  4 ],
    [  506,  200000000,  2, 64, 36,  2 ],
    [  507,  200000000,  1, 64, 36,  1 ],
    [  600,  200000000, 35, 64, 36, 36 ],
    [  601,  200000000, 18, 64, 36, 18 ],
    [  602,  200000000, 12, 64, 36, 12 ],
    [  603,  200000000,  9, 64, 36,  9 ],
    [  604,  200000000,  6, 64, 36,  6 ],
    [  605,  200000000,  4, 64, 36,  4 ],
    [  606,  200000000,  2, 64, 36,  2 ],
    [  607,  200000000,  1, 64, 36,  1 ]
])


def main():
    print HARDWARE_INFOS[23]


if __name__ == "__main__":
    main()
Torsten2000
User
Beiträge: 40
Registriert: Montag 27. Dezember 2010, 17:26

Hallo BlackJack,

ich muss mich schon wieder für deine ausgezeichnete Antwort bedanken!

Ich brauche nicht die tatsächliche C-Datenstruktur, sondern einfach nur die Informationen als Python-Datentypen/-Strukturen?

Deine Antwort ist genau passend für mich :-)
Vielen dank dafür!

Hast du eigentlich ein "Dankeschönkonto" für deine Hilfe?

Viele Grüße
Torsten
BlackJack

@Torsten2000: Man könnte mich "flattrn" (wenn man dazu in der Lage ist): http://imflattrd.com/BlackJack

Über die Verwendung meines Dropbox-Referrer-Codes würde ich mich auch freuen.

Aber ich mache das ja nicht wegen Geld oder Speicherplatz, sondern wegen der Freude am Helfen. Oder der Freude am Anfänger zum weinen bringen. Kommt drauf an wen man fragt. :twisted:
Torsten2000
User
Beiträge: 40
Registriert: Montag 27. Dezember 2010, 17:26

Ich habe es geschafft, alle meine Fehler auszumerzen und den LA zum laufen zu bringen.

An dieser Stelle möchte ich mich nochmal ganz herzlich bei lunar und ganz besonders an BlackJack bedanken!

@BlackJack
Flattern kann ich dich nicht. Dropbox müsste ich mich anmelden...
ich könnte dir von meinem FTP-Speicher was abgeben...
Ich habe da SEHR viel und könnte dir ein Account einrichten? Würde dir das auch weiter helfen?

Viele Grüße
Torsten
BlackJack

@Torsten2000: Nee, lass mal gut sein. Ich mache das hier ja aus Spass an Python und für mein Ego. :-) Das reicht als Lohn.
Torsten2000
User
Beiträge: 40
Registriert: Montag 27. Dezember 2010, 17:26

Hallo,
da bin ich nochmal...

ich versuche gerade mein Code "Python-Konformer" zu gestalten.

ich hatte bei den "def load_settings_from_file():" nie ein "self" drin... damit hat es super funktioniert...

aber laut Tutoriom soll das erste Argument "self" sein.
Gesagt getan und jetzt kommt der Fehler:

TypeError: set_travel_logic_mode() takes exactly 2 arguments (1 given)

muss man das "self" nur innerhalb von einer Klasse schreiben?

Ich habe eine Datei und dadrin die Funktionen. Brauche ich da nicht das "self"?

Sollte ich die Funktonen in eine Klasse packen?

PS: komischerweise funktioniert es bei machen Funktionen schon!?!

Danke schön
Grüße Torsten
Benutzeravatar
/me
User
Beiträge: 3555
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

Torsten2000 hat geschrieben:muss man das "self" nur innerhalb von einer Klasse schreiben?
Ja. Schau dir mal das Tutorial zu Klassen an. Wenn es zu schwierig wird, dann beginne weiter vorne um dir noch etwas mehr von den Grundlagen anzueignen.
Torsten2000 hat geschrieben:Sollte ich die Funktonen in eine Klasse packen?
Das ist eine Frage des Codedesigns. Wenn es sinnvoll ist eine Klasse zu haben, dann verwende sie. Wenn nicht, nicht.

Es ist schwierig dafür eine genaue Handlungsanweisung zu geben. Die Erfahrung in der Softwareentwicklung macht da einiges aus. Du solltest allerdings nicht Funktionen nur deshalb in einer Klasse zusammenpacken "weil sie zusammen gehören". Eine Klasse ist kein Selbstzweck und ihre Existenz sollte schon einen sinnvollen Grund haben.
Torsten2000
User
Beiträge: 40
Registriert: Montag 27. Dezember 2010, 17:26

Hallo Python-Freunde,

ich habe schon wieder ein Problem...

Ich habe eine andere DLL erhalten, die ich gerne in mein Projekt einbinden würde. Eigentlich dachte ich kein Problem, da ich ja schon eine eingebunden habe...

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 versucht einzubinden

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)
Aber zu viele Argumente sind das doch gar nicht... und die richtige größe haben sie doch auch, oder?
Mache ich da was falsch oder stimmt was mit der DLL nicht?

Vielen Dank
Grüße
Torsten
deets

Wenn was mit der DLL "nicht stimmen" wuerde, dann wuerdest du keine nette Python-Exception bekommen, sondern einfach einen segfault (oder wie auch immer das unter Windows heisst, wenn ein Programm abstuerzt).

Ctypes ist immer ein bisschen Fummelig, aber mir sieht es danach aus, als ob du deine Wave und Wave_of_channel Argumente falsch uebergibst. Du erzeugst *arrays*, aber willst pointer auf arrays uebergeben. normalerweise geht mE sowas nicht so ohne weiteres.

Ich denke, hier fehlt mindestens mal ein byref um Wave und Wave_of_channel herum. Und dann meckert der wahrscheinlich, dass du versuchst ein POINTER(c_byte) mit einem POINTER(array_c_byte_80) (die tatsaechlichen Meldungen sind etwas anders, aber die Richtung stimmt) zu bestuecken. Das heisst, das du da noch ein cast auf POINTER(c_byte) brauchst.
BlackJack

@Torsten2000: Das sind 4 Byte pro Argument -- versuchst Du vielleicht von einem 64-Bit-Python eine 32-Bit-DLL zu verwenden?
Torsten2000
User
Beiträge: 40
Registriert: Montag 27. Dezember 2010, 17:26

Hallo BlackJack,

danke für die schnelle Antwort.
Das Python ist eine 32Bit. Ich benutze WinXP 32Bit. Ebenso die "IDLE (Python GUI)" ist 32bit
Torsten2000
User
Beiträge: 40
Registriert: Montag 27. Dezember 2010, 17:26

@ deets
jetzt habe ich doch glatt übersehen, dass du eine Nachricht geschrieben hast. Entschuldige. Auch dir ein Danke schön für deine schnelle Antwort.

Hier die zwei Fehlermeldungen, die er bringt, wenn ich die Arrays caste.
_unmangle( byref(Wave), sizeof(Wave), Channel, byref(Wave_of_channel), sizeof(Wave_of_channel), P1, P2, P3)
ArgumentError: argument 1: <type 'exceptions.TypeError'>: expected LP_c_byte instance instead of pointer to c_byte_Array_80
_unmangle( POINTER(c_byte)(byref(Wave)), sizeof(Wave), Channel, POINTER(c_byte)(byref(Wave_of_channel)), sizeof(Wave_of_channel), P1, P2, P3)
TypeError: expected c_byte instead of CArgObject
Antworten