Seite 1 von 1
ctypes & callback funktionen
Verfasst: Dienstag 29. Mai 2012, 09:54
von ScooB
Hi
ich hab da mal ne Frage
ich hab da ne C++ Funktion
Code: Alles auswählen
AdsSyncAddDeviceNotificationReq(pAddr, ADSIGRP_SYM_VALBYHND, hUser, &adsNotificationAttrib, Callback, hUser, &hNotification);
dich ich über Ctypes aufrufe
Code: Alles auswählen
error = self.ads_library.AdsSyncAddDeviceNotificationReq(ctypes.pointer(self.padress),ads_struct.ADSIGRP_SYM_VALBYHND,handel, adsNotificationAttrib, tempcall ,handel, hNotification)
was auch soweit Funktioniert das ich keinen error zurück bekomme.
Problem an die Funktion wird ne Callback Funktion übergeben die dann immer Werte erhält und verarbeitet.
Meine Frage ist wie kann ich die Callback-Funktion umsetzen in Python
Den Orginal C++ Code kann man sich unter folgendem Link anschauen
http://infosys.beckhoff.com/index.php?c ... m&id=11350
Die Callback Funktion ist nicht in einer der C++ Bibliothek enthalten sie ist nur in dem Bsp-Code enthalten und ich möchte in Python halt eine eigene schreiben.
Danke schon mal, bin über jeden Tip dankbar
Gruß ScooB
Re: ctypes & callback funktionen
Verfasst: Dienstag 29. Mai 2012, 10:43
von snafu
Re: ctypes & callback funktionen
Verfasst: Dienstag 29. Mai 2012, 10:52
von ScooB
Soweit bin ich auch schon gekommen
Code: Alles auswählen
def callback2(self, pAddr, pNotification, hUser):
print 'test', pAddr, pNotification, hUser
print pNotification.data
return 5
Code: Alles auswählen
cf=ctypes.CFUNCTYPE(None, ctypes.POINTER(ads_struct.PAmsAddr), ctypes.POINTER(ads_struct.AdsNotificationHeader), ctypes.POINTER(ctypes.c_ulong))
callback = cf(self.callback2)
und callback dann übergeben
aber tut sich leider nichts
Re: ctypes & callback funktionen
Verfasst: Dienstag 29. Mai 2012, 11:05
von Dav1d
So wie ich die Dokumentation verstehe sollte das so aussehen (vorrausgesetzt, dass deine Argumente richtig sind):
Code: Alles auswählen
cf=ctypes.CFUNCTYPE(c_int, ctypes.POINTER(ads_struct.PAmsAddr), ctypes.POINTER(ads_struct.AdsNotificationHeader), ctypes.POINTER(ctypes.c_ulong))
Und der Callback (self hat da nichts zu suchen):
Code: Alles auswählen
def callback(pAddr, pNotification, hUser):
print 'test', pAddr, pNotification, hUser
print pNotification.data
return 5
Re: ctypes & callback funktionen
Verfasst: Dienstag 29. Mai 2012, 13:01
von snafu
@Dav1d (bzgl. `self`): Der OP scheint den Callback als Methode implementiert zu haben, wo ja dann schon ein `self` hin muss. Ob das einen Unterschied für `ctypes` macht, weiß ich nicht. Könnte man natürlich ausprobieren. Bin ich aber gerade zu faul für.
Ansonsten halt mal abwarten, ob BlackJack oder so noch was dazu sagen kann. Ich hab offen gestanden zu wenig Ahnung von `ctypes`, um jetzt irgendeine weitergehende Problemanalyse zu machen...
Re: ctypes & callback funktionen
Verfasst: Dienstag 29. Mai 2012, 15:53
von jerch
Hab das gerade mal getestet, bei mir funktioniert das auch mit Methoden, selbst der Zugriff auf ein anderes Attribut wird richtig ausgeführt:
Code: Alles auswählen
>>> from ctypes import *
>>> shared=cdll.LoadLibrary('libtest.so')
>>> f_proto = CFUNCTYPE(c_int, c_int)
>>> class Bar(object):
... def __init__(self):
... self.v = 10
... def f(self, a):
... return self.v + a
...
>>> bar=Bar()
>>> f_obj = f_proto(bar.f)
>>> shared.test(10, f_obj)
20
>>> shared.test(0, f_obj)
10
Die c-Funktion:
Code: Alles auswählen
int test(int a, void *cb) {
int (*f)(int);
f = cb;
return f(a);
}
Allerdings weiss ich nicht, ob bzw. wie gut die Benutzung von Methoden offiziell unterstützt wird. Das self scheint zumindest für die Deklaration kein Problem zu sein.
Re: ctypes & callback funktionen
Verfasst: Dienstag 29. Mai 2012, 16:00
von deets
Das ist prinzipiell egal. Es geht um ein callable, und eine bound method ist ein callable. Solange eine Referenz darauf existiert (und die haelt ctypes ja selbst), geht das also.
Re: ctypes & callback funktionen
Verfasst: Dienstag 29. Mai 2012, 16:09
von Dav1d
Interessant, ich dachte das ginge nicht.
Re: ctypes & callback funktionen
Verfasst: Mittwoch 30. Mai 2012, 08:09
von ScooB
Mal was anderes wie halte ich das "Programm" am laufen weil wenn ich es ausführe wird es danach beendet.
Oder soll ich die Funktion in nen eigenen Thread packen??
Ich steh echt auf'm Schlauch und komm nicht weiter mit der Sache.
Also nur damit man es versteht was ich da mache.
Ich möchte werte aus ner SPS lesen wenn sie sich verändern, dafür gibt es die Funktion AdsSyncAddDeviceNotificationReq(...) (welche in der Bibliothek enthalten ist, die Callback nicht) mit der man sozusagen eine Variable der SPS überwacht und falls sie sich ändert eine Funktion aufgerufen wird. In C++ Funktioniert das ganze ja auch, nur ich soll es halt in Python umsetzen.
Mein Status ist soweit das wenn ich die AdsSyncAddDeviceNotificationReq() aufrufe die Notification regestriert wird und was auch gut ist, nur wie vielleicht schon gemerkt steh ich halt bei der Callback Funktion auf dem schlau.
Falls nützlich hier mein "Test-herumspiel-Code", bei der Callback habe ich mal nen Return mal keinen nur damit ihr nicht drucheinander kommt is halt mein Testcode
Code: Alles auswählen
class Ads:
#ADS Bibliothek Laden
ads_library = ctypes.windll.LoadLibrary(r'C:\TwinCAT\ADS Api\TcAdsDll\TcAdsDll.dll')
padress = 0
def __init__(self, ip=None):
self.connect()
def __del__(self):
self.disconnect()
def connect(self):
port = self.ads_library.AdsPortOpen()
self.padress = ads_struct.PAmsAddr()
self.ads_library.AdsGetLocalAddress(ctypes.pointer(self.padress))
self.padress.port = ads_struct.AMSPORT_R0_PLC_RTS1
return self.padress
def disconnect(self):
error = self.ads_library.AdsPortClose()
def callback(self):
print 'test callback'
def callback2(self, pAddr, pNotification, hUser):
print 'test', pAddr, pNotification, hUser
print pNotification.data
def notification(self, var_name):
var_name = ctypes.create_string_buffer(var_name)
adsNotificationAttrib = ctypes.pointer(ads_struct.AdsNotificationAttrib())
adsNotificationAttrib.cbLength = 4
adsNotificationAttrib.nTransMode = ads_struct.ADSTRANS_SERVERONCHA
adsNotificationAttrib.nMaxDelay = 0
adsNotificationAttrib.nCycleTime = 10000 #1000000
adsNotificationAttrib.dwChangeFilter = 10000 #1000000
handel = ctypes.c_ulong(0)
hNotification = ctypes.c_ulong(0)
cf=ctypes.CFUNCTYPE(None, ctypes.POINTER(ads_struct.PAmsAddr), ctypes.POINTER(ads_struct.AdsNotificationHeader), ctypes.POINTER(ctypes.c_ulong))
tempcall = cf(self.callback2)
error = self.ads_library.AdsSyncReadWriteReq(ctypes.pointer(self.padress),ads_struct.ADSIGRP_SYM_HNDBYNAME,0x0, ctypes.sizeof(handel), ctypes.pointer(handel), ctypes.sizeof(var_name),ctypes.pointer(var_name))
print error, "error 1"
error = self.ads_library.AdsSyncAddDeviceNotificationReq(ctypes.pointer(self.padress),ads_struct.ADSIGRP_SYM_VALBYHND,handel, adsNotificationAttrib, tempcall,handel, ctypes.pointer(hNotification))
print error, "error 2"
print hNotification , 'hNotification'
error = self.ads_library.AdsSyncDelDeviceNotificationReq(ctypes.pointer(self.padress), hNotification)
print error, "error 3"
test = Ads()
test.notification('MAIN.PLCVar0')
Re: ctypes & callback funktionen
Verfasst: Montag 4. Juni 2012, 09:03
von ScooB
Keiner nen Tip ???
Re: ctypes & callback funktionen
Verfasst: Montag 4. Juni 2012, 09:22
von deets
Ob das reicht? KA. Kenne deine Lib ja nicht, ob die einen mainloop call braucht. Oh, und __del__ gewoehn dir mal ganz schnell ab. Explizites resourcen-management ist zuverlaessiger, es gibt keine Garantie von Python das __del__ ueberhaupt aufgerufen wird.
Re: ctypes & callback funktionen
Verfasst: Montag 4. Juni 2012, 11:13
von ScooB
Nein Das reicht aus leider

Re: ctypes & callback funktionen
Verfasst: Montag 4. Juni 2012, 13:02
von deets
Ich nehme mal an du meinst "reicht *nicht* aus".
Dann musst du halt schauen, wie deine Lib periodisch aufgerufen werden will.