Hallo, ich arbeite hier an einer Software, die mittels DAQ-Karten von Advantech (PCIE-1744) Messungen durchführen soll. Dabei kommt der DAQNavi-Treiber zum Einsatz. System ist ein 32Bit Windows XP und Delphi 2010. Die OLE-Komponente für den Analog Input löst immer dann ein Event aus, wenn Daten im Puffer des Treibers zum abholen bereit stehen. Dem Event eine Behandlungsroutine zuzuweisen ist kein Problem. Jedoch belastet das Event den Main-Thread der Applikation, der auch so schon recht viel zu tun hat. Die Behandlungsroutine ist schon so kurz wie möglich gehalten und kopiert die Daten nur in einen anderen Puffer zur Weitervarbeitung um. Sinnvoll wäre es jetzt, auch da das Zielsystem über 8 Kerne verfügt, wenn ein zusätzlicher Thread auf das Event reagieren würde und das kopieren erledigt. Im Moment ist es so, dass das Event normal ausgelöst wird und nur ein Flag gesetzt wird. Der Thread zum kopieren fragt dieses Flag dann regelmäßg ab und startet bei Bedarf den Kopiervorgang. Ich hätte jetzt aber gern, dass der Thread dirket auf das (und andere) Event des Treibers reagieren würde, so dass der Main-Thread komplett außen vor bleibt. Ich weiß nur leider nicht, wie ich das anstelle. Meine Suchen zu dem Thema waren bisher erfolglos. Vielleicht fehlt mir auch nur der richtige Begriff. Hat jemand von euch shconmal so etwas gemacht? Vielen Dank, Christian
Hi! Also mein Delphi-Wissen ist schon etwas her, aber ich bin der Meinung, dass immer nur der GUI-Thread selbst in der Lage ist Events abzuarbeiten. Events sind keine direkten Closures und funktionieren intern über WINDOWS-Nachrichten. So weit mir bekannt war es unter Delphi/BCB schon immer problematisch bis unmöglich, Forms in einem neuen Thread zu erstellen. Theoretisch könnte man dann diesem neuen Form die Abarbeitung der Events überlassen (indem man den Event zur Laufzeit zuweist, also z.B. Komponente->MeinEvent = ThreadForm->MeineEventFunktion). Darauf würde ich mich aber nicht einlassen und lieber so arbeiten, wie Du es jetzt schon machst. Anstatt ein Flag zu setzen (was der Thread dann pollt) solltest Du lieber mit einem oder mehreren TEvents (die haben lustigerweise NICHTS mit den oben genannten Events gemein...) arbeiten, auf die der Thread dann wartet. Bei einem Event mit TEvent->WaitFor() bei mehreren mit WaitForMultipleObjects und Konsorten. Gruß, Oliver
Oliver R. schrieb: > aber ich bin der Meinung, > dass immer nur der GUI-Thread selbst in der Lage ist Events > abzuarbeiten. Events sind keine direkten Closures und funktionieren > intern über WINDOWS-Nachrichten. Wenn "Event" ein Event im Sinne der Win32-API meint, dann irrst Du Dich glücklicherweise. Ein Thread wartet auf ein Event mit den Funktionen WaitForSingleObject bzw. WaitForMultipleObjects. Erzeugt wird ein Event mit CreateEvent, signalisiert wird es mit SetEvent bzw. ResetEvent (letzteres ist nur bei nicht-automatisch rücksetzenden Events erforderlich). Das funktioniert mit allen Threads und hat nichts mit Windows-Nachrichten zu tun.
Hi, Rufus Τ. Firefly schrieb: > > Wenn "Event" ein Event im Sinne der Win32-API meint, dann irrst Du Dich > glücklicherweise. > Nein, das meinte ich nicht. Borland (bzw. deren unaussprechliche Nachfolger) bezeichnen einen VCL-Event als Behandlungsereignis einer Komponente (meistens Oberfläche, z.B. ein Button). Das wird dann vom Dispatcher des Hauptthreads abgearbeitet. Nun gibt es da noch das Objekt "TEvent", welches die von Dir genannten WIN32-API-Events kapselt. Leider vom Sprachgebrauch sehr ähnlich, aber konzeptionell absolut nicht miteinander verwandt. Gruß, Oliver
Ich mach ueblicherweise auch solche Dinge, hab's aber nicht grad zugriffsbereit. In der Zwischenzeit empfehle ich das Embarcadero Forum. Die Experten sind dort.
Oliver R. schrieb: > Nein, das meinte ich nicht. Borland (bzw. deren unaussprechliche > Nachfolger) bezeichnen einen VCL-Event als Behandlungsereignis einer > Komponente (meistens Oberfläche, z.B. ein Button). Das wird dann vom > Dispatcher des Hauptthreads abgearbeitet. Ja, um solch ein Event handelt es sich. Zumindest bin ich mir da sicher, es sieht so aus, riecht so und schmeckt so wie auch z.b. ein OnClik-Event eines TButtons. Ich zitiere mal aus der TLB zum Treiber:
1 | TBufferedAiCtrl = class(TOleControl) |
2 | private |
3 | FOnDeviceRemoved: TNotifyEvent; |
4 | FOnDeviceReconnected: TNotifyEvent; |
5 | FOnPropertyChanged: TNotifyEvent; |
6 | FOnDataReady: TBufferedAiCtrlDataReady; |
7 | FOnOverrun: TBufferedAiCtrlOverrun; |
8 | FOnCacheOverflow: TBufferedAiCtrlCacheOverflow; |
9 | FOnStopped: TBufferedAiCtrlStopped; |
10 | FIntf: IBufferedAiCtrl; |
11 | [...] |
12 | property OnDeviceRemoved: TNotifyEvent read FOnDeviceRemoved write FOnDeviceRemoved; |
13 | property OnDeviceReconnected: TNotifyEvent read FOnDeviceReconnected write FOnDeviceReconnected; |
14 | property OnPropertyChanged: TNotifyEvent read FOnPropertyChanged write FOnPropertyChanged; |
15 | property OnDataReady: TBufferedAiCtrlDataReady read FOnDataReady write FOnDataReady; |
16 | property OnOverrun: TBufferedAiCtrlOverrun read FOnOverrun write FOnOverrun; |
17 | property OnCacheOverflow: TBufferedAiCtrlCacheOverflow read FOnCacheOverflow write FOnCacheOverflow; |
18 | property OnStopped: TBufferedAiCtrlStopped read FOnStopped write FOnStopped; |
19 | end; |
Konkret geht es um die Events OnDataReady, OnOverrun und OnCacheOverflow. Für WaitForMultipleObjects() benötigt man ja den Handle des Events. Nur, wie bekomm ich den raus?
Hi, also nochmal: Die VCL-Events (die Events Deiner Komponente) haben NICHTS mit den WIN32-API-Events zu tun. Deshalb gibt es da auch kein Handle. Aber Du kannst in Deinem OnDataReady-VCL-Event ein WIN32-API-Event-Objekt, welches durch das Delphi-Objekt "TEvent" gekapselt wird, signalisieren, dass neue Daten da sind. Dafür legst Du im Konstruktor Deines Forms ein oder mehrere TEvent-Objekte an und wartest in Deinem Thread auf diese Objekte, ob was passiert. Damit vermeidet man das Polling des Threads auf irgendwelche Flags. Desweiteren musst Du bei deinem Form aufpassen, dass es NIE durch längere Aktionen blockiert wird. Dann blockiert nämlich auch der Dispatcher und es werden keine VCL-Events abgearbeitet. Evtl. gibt es bei Deiner OLE-Komponente aber auch noch die Möglichkeit, synchron auf neue Daten zu warten (also. z.B. Komponente->WaitForNewData()). Das könnte man dann direkt im Thread machen und man würde auf Events ganz verzichten. Gruß, Oliver
Oliver R. schrieb: > Damit vermeidet man das Polling des Threads auf irgendwelche Flags. > Desweiteren musst Du bei deinem Form aufpassen, dass es NIE durch > längere Aktionen blockiert wird. Das ist Standard bei OOP und Ereignissteurerung und keine Besonderheit von Delphi. Hier Hintergrundinformation zum Thema: http://www.delphi-treff.de/tutorials/vcl/komponenten-entwicklen/ereignisse-events/
Hallo, leider kann ich zu Delphi nichts sagen. Wir nutzen C++, mit der DAQ NAVI Umgebung. Die Daten werden in einer DataHandlerKlasse, welche vom Advantech DaqNavi BfdAiEventListener erbt, verarbeitet. Die Kartensoftware ruft darin die Memberfunktion BfdAiEvent(void * sender, BfdAiEventArgs * args) auf, wenn Daten verfügbar sind. Die Daten werden dann mittels der Funktion GetData(sampleCount, m_dataPtr); in einen lokalen Speicher geschrieben und können dann von einem anderen Thread verarbeitet werden. Den Speicher für die Daten muss man selbst zur Verfügung stellen. ABER wir haben eine solche Karte Anfang des Jahres in einem System eingesetzt. Es hat sich nun herausgestellt, dass die Karte zumindest in unserem System ihre Sample-Rate absolut nicht einhält. Die von Advantech mitgelieferte DAQNavi Applikation zeigt im Testmode bei periodischen Signalen bei jedem Start immer mal wieder mit falscher Rate abgetastete Daten im Testdisplay an. Wir verwenden 10 MS/s und die Daten werden gelegentlich mit 20 MS und auch langsamer abgetastet. Mich würde mal interessieren, ob das bei Euch auch so ist. Hinzu kommt, dass die PCIE-1744 Karte eine PCIe-PCI Bridge enthält, die nach Aussage von Adv. eine zusätzliche Latency in den Interrupt betrieb hineinbringt und so bei höheren Raten kritisch wird. Wir haben jetzt die PCI Version der Karte also die PCI 1714 geordert in der Hoffnung die Probleme zu vermeiden.
Hallo CIMS_ES, dass die Samplerate manchmal nicht korrekt gesetzt ist, ist mir mit den Demoapplikationen auch schon einmal aufgefallen (unter Delphi). Bzw. ist mir dort aufgefallen, dass eben bei angelegten Rechtecksignal zwischen zwei Starts ab und an unterschiedlich viele Perioden zu sehen waren. Hab es aber nicht untersucht und auf die Darstellung geschoben. Bei unserer Software bzw. Anwendung benötigen wir nur einen kleinen Aussschnitt mit hoher Auflösung, weshalb nach die restlichen Daten verworfen werden. Nach manchen Starts kann die Software zwar triggern, aber in dem aufgezeichneten Ausschnitt ist nur Rauschen, aber nicht das zu untersuchende Signal. Das würde dazu passen, dass die Samplerate nicht richtig gesetzt ist. Was aber noch viel schlimmer ist, vor allem für unsere Anwendung: unter Delphi mit der ActiveX Typbibliothek sind die Kanäle nicht alle synchron. Also Kanal 1 zu 2 und 3 zu 4 bleiben synchron, aber die beiden Paare laufen auseinander. Das tritt bei unserer Software als auch bei den Examples auf. Unter C# mit der .net-Typbibliothek passiert das nicht. Ebenfalls merkwürdig: nach mehrmaligen Starten der Applikation ist irgendwann die Karte nicht mehr ansprechbar und Windows muss neu gestartet werden. Wir versuchen es jetzt erst einmal noch mit Workarounds.
Christian S. schrieb: > Konkret geht es um die Events OnDataReady, OnOverrun und > OnCacheOverflow. Für WaitForMultipleObjects() benötigt man ja den Handle > des Events. Nur, wie bekomm ich den raus? Sieht für mich eher nach Window Message Handlern aus - TOleControl erbt aus TWinControl. Die werden in dem Thread behandelt, der das Window erstellt hat. Du musst also dein TBufferedAiCtrl in einem Thread erstellen, der auch eine Message Loop enthält. Es kann sein, dass die Message Queue vorher mit einem Call zu PeekMessage() "scharf" gestellt werden muss.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.