(18.06.2012 12:50 )Event Horizon schrieb: Hallo zusammen!
Ich habe hier ein USB-Oszilloskop, welches eine größere Anzahl Waveforms speichern kann.
Die beiliegenden DLLs enthalten eine Funkion, um den Buffer für jede einzelne Waveform festzulegen, sowie eine weitere Funktion, die die Daten anschließend aus dem Scope in die Buffer überträgt. In C sieht das etwa so aus:
Code:
int buffer1[1000];
int buffer2[1000];
int buffer3[1000];
Scope::SetBuffer(1, buffer1);
Scope::SetBuffer(2, buffer2);
Scope::SetBuffer(3, buffer3);
Scope::GetValues();
Nun sind es nicht nur 3 Buffer, sondern eher sowas wie 1000-10000, die Anzahl soll dynamisch sein.
In C macht man sich dann ein 2D-Array buffer[a][b], und übergibt der Funktion dann die einzelnen Subarrays buffer[a].
In Labview 8.6 bekomme ich das so statisch wie in dem COde-Beispiel hin, aber nicht dynamisch, da ich Probleme mit den Subarrays habe.
Ein Versuch war, für jede Wafeform ein einzelnes 1D-Array anzulegen, in die DLL-Funktion zu stopfen, und hinten zu nem 2D-Array zusammen zu tackern:
(Das ist grade auf die Schnelle hingemalt)
Problem: Beim Zusammentackern werden die Arrays intern an andere Speicherstellen verschoben, der nachfolgende AUfruf von GetValues führt dann lieber zum Crash von LV.
Ich könnte auch zuerst ein 2D-Array erzeugen, und dem SetBuffer Subarrays davon mitgeben. Funktioniert nicht, da bei den Subarrays offensichtlich immer Kopien der Daten erstellt werden.
Mäßigen Erfolg hatte ich mit Queues, in die ich die einzelnen Arrays stopfe. Crasht aber, wenn es zu viele Arrays werden.
Hat wer ne Idee, was ich da in LV 8.6 machen kann?
Das geht so wie Du es tust absolut nicht.
1) Wenn die C Funktion einen Buffer von einer bestimmten Länge haben will musst DU den in LabVIEW auch allozieren und an die C Funktion übergeben, denn die C Funktion kann diesen Buffer nicht einfach vergrösseren wenn nötig, so wie LabVIEW das automatisch tut solange Du im Diagramm bleibst. Typisch macht man das mit der Initilize Array Funktion, aber......
2) LabVIEW Arrays sind nur während der Dauer des C Funktionsaufrufes garantiert um dort zu bleiben wo sie am Anfang des Aufrufs der C Funktion waren, danach ist LabVIEW frei um diese Arrays frei zu geben, wieder zu verwenden oder an einer anderen Stelle im Speicher zu verschieben. Diese Einschränkung lässt sich nicht wirklich entfernen, denn die ganze Optimalisierung von Speicherplatz und Ausführungszeit in LabVIEW beruht darauf dass LabVIEW den Speicher von Datenstrukturen jederzeit frei verschieben darf wenn es dies als notwendig erachtet.
Das einzige was Du tun kannst ist in der Loop selber jeweils einen Speicherbereich zu allozieren mit einem Aufrufe einer Speichermanagerfunktion und den daraus ergebenden Pointer an die Funktion zu geben. Und danach nach dem Du sicher weisst dass die DLL diese Buffer gefüllt hast, die Informationen aus diesem Pointer in eine genügend grosses LabVIEW Array kopieren. Und zu guter letzt auch nicht vergessen um jeden Pointer wieder ganz ordentlich zu deallozieren, ansonsten baust Du gewaltige Speicherlecks.
Dasselbe Problem hast Du übrigens in jeder Managed Umgebung wie etwa auch .Net wenn Du so ein Unmanaged API ansprechen willst.
Bedenke auch dass LabVIEW Datenflow ist und dass Daten im Wire zwar durch LabVIEW als Referenz benützt werden können zur Optimalisierung aber dass die Daten grundsätzlich immer By Value gesehen werden sollten. Der Pointer den Du mit SetBuffer an die DLL übergibst ist also möglicherweise einfach eine Kopie des ürsprünglichen Arrays, die nach dem Aufruf der Funktion freigegeben, da nicht mehr verwendet wird. Damit schribt GetValues in nun ungültigen Speicher und selbst wenn dieser Speicher nicht dealloziert wäre, würde GetValues in eine Kopie des ursprünglichen Arrays schreiben und nicht in das Array das Du dann im Indicator anzeigst.
Grundsätzlich ist also zu sagen dass dieses Oszi API nur von C aus zuverlässig aufgerufen werden kann und auch nur wenn Du einiges über Speicherverwaltung und Pointer weisst. Höhere Programmierumgebungen stolperen ganz einfach über das Problem, dass diese Managed Code voraussetzen und im Absenz verlangen, dass der Aufrufer des Unmanaged APIs die ganze Verwaltungsarbeit selber übernimmt.