Wenn dein Problem oder deine Frage geklärt worden ist, markiere den Beitrag als "Lösung",
indem du auf den "Lösung" Button rechts unter dem entsprechenden Beitrag klickst. Vielen Dank!
Ich möchte einen Speicherbereich reservieren um den Speichermanager selbt im Griff zu haben.
Dazu sollte mittels eines Arrays (BxHxBit --> für Bild) der Speicher reseviert werden und ein Pointer auf diesen Speicherbereich ausgegeben werden (mit diesem kann ich dann Bilder auf einen bestimmten Speicherplatz schreiben). Diesen Aufruf möchte ich in einem SubVI durchführen (ähnlich der Funktion die VISION bietet -->Image_Create) den Pointer anderweitig verwenden um ein Bild hinein zu speichern.
In einem anderen SubVI sollte dieser Speicherbereich dann wieder freigegeben werden können (um keinen Speicherüberlauf zu generieren).
Die Frage ist nun, wie ich diese Funktion in LabVIEW (ohne VISION) implementieren kann?? (muß ich hierzu eine dll schreiben oder geht es mit LV Bordmitteln?)
Developer Suite Core -> LabVIEW 2015 Prof.
2006
EN
71083
Deutschland
Buffer reservieren + Pointer auslesen
Es gibt in LabVIEW ein paar Speicherfunktionen (vgl. Screenshot). Vielleicht ist da was für Dich dabei.
Gruß Markus
-------------------------------------------------------------------------- Bitte stellt mir keine Fragen über PM, dafür ist das Forum da - andere haben vielleicht auch Interesse an der Antwort !!
--------------------------------------------------------------------------
' schrieb:Ich möchte einen Speicherbereich reservieren
Darüber lass ich mit mir ja noch reden.
Zitat:um den Speichermanager selbt im Griff zu haben.
Weißt du was das heißt: "Speichermanager im Griff haben"? Bitte nicht den Speichermanager, wenn dann diesen einen Speicherbereich.
Zitat:Dazu sollte mittels eines Arrays (BxHxBit --> für Bild) der Speicher reseviert werden und ein Pointer auf diesen Speicherbereich ausgegeben werden (mit diesem kann ich dann Bilder auf einen bestimmten Speicherplatz schreiben). Diesen Aufruf möchte ich in einem SubVI durchführen (ähnlich der Funktion die VISION bietet -->Image_Create) den Pointer anderweitig verwenden um ein Bild hinein zu speichern.
In einem anderen SubVI sollte dieser Speicherbereich dann wieder freigegeben werden können (um keinen Speicherüberlauf zu generieren).
Dieses Vorgehen an sich mag sinnvoll sein. Nur: In LV, zumindest auf der Oberfläche, auf der sich der Programmierer befindet, gibt es keine Pointer.
Zitat:Die Frage ist nun, wie ich diese Funktion in LabVIEW (ohne VISION) implementieren kann??
Vielleicht geht es mit Bordmitteln. Aber einfach wird das nicht.
Frage:
Warum willst du denn überhaupt einen Pointer haben und mit dem arbeiten? Normalerweise würde alles mit einen funktionalen SubVI machbar sein.
Jeder, der zur wahren Erkenntnis hindurchdringen will, muss den Berg Schwierigkeit alleine erklimmen (Helen Keller).
Du initialisierst ein 1D-Array mit der Größe BxHxBit/8, drahtest dieses an den Eingang des Pointers des DLL-Aufrufs an und stellst als Typ "Array, U8, Array Data Pointer" ein.
Das funktioniert bei einer dll in einem Projekt von mir, die was ganz ähnliches macht (Ein Bild einer kamera in einen per zeiger übergebenen Speicherbereich schreiben) ganz gut.
Meine Anschlussfrage ist nun allerdings:
Meine dll muss 2 Mal aufgerufen werden: Beim ersten Mal wird die Anfangsadresse des allokierten Speichers übergeben, Funktion:
INT is_SetAllocatedImageMem (HIDS hf, INT width, INT height, INT bitspixel, char* pcImgMem, int* pid)
beim zweiten Mal wird dieser Speicher an einen Ringpuffer angehängt:
INT is_AddToSequence (HIDS hf, char* pcImgMem, INT nID)
Der zweite Teil funktioniert nun leider nur beim 1. Durchlauf einer Schleife. Ab dem 2. Aufruf klappt es nicht mehr, es wird ein Fehlercode aus der dll zurückgegeben. Und zum debuggen würde ich nun gern sehen, on mglw. beim 2. Aufruf die selbe Speicheradresse übergeben wurde. Dann könnte ich verstehen, daß die Ringpuffer-Funktion da meckert.
Das verrückte ist noch: Mache ich den 2. Aufruf nicht in einer Schleife, sondern einfach durch eine nachgeschaltete Kopie der beiden Aufrufe, dann funktioniert es! Verrückt.
Ich muss aber leider ca. 90 Frames allokieren, und kann/will diese beiden Funktionen nicht neunzigmal hintereinander kopieren.
Wie kann man sich denn also die tatsächliche Speicheradresse ausgeben lassen, die der dll übergeben wird? Damit könnte ich das mal überprüfen, ob die Crux schon beim Allokieren liegt.
Es gibt nun darüberhinaus noch eine weitere Funktion der dll:
INT is_AllocImageMem (HIDS hf, INT width, INT height, INT bitspixel, char** ppcImgMem, INT* pid)
Damit wird der Speicher dll-intern selbst allokiert. Ausgegeben wird hier nun wiederum die Speicheradresse. Diese bekomme ich diesmal allerdings nicht als Array-Pointer, sondern in den ersten 4 Stellen IM Array. Da wäre nun die Frage andersherum: Wie mache ich aus dieser Rückgabe wieder einen Pointer, um diesen der Ringpuffer-Funktion zu übergeben?
Danke schonmal für alle Hinweise.
Ich arbeite übrigens mit einer ueye-Kamera von ids-imaging. Hat jemand vielleicht sogar speziell mit deren dlls und LabVIEW Erfahrungen?
Wenn dll Buffer alloziert, ist das sicherlich nicht schlecht. Dann gibt es keinen Ärger mit dem LV-Speichermanager.
Ich würde dann "char** ppcImgMem" entweder als U32 oder als Pointer zu U32 definieren. Damit bekommst du die Anfangs-Adresse des Buffers zurück. Dieses Wert übergibst du dann einfach als Wert an die AddToSequence-Funktion. Soll heißen, bei dieser Funktion definierst du das nicht als char*, sondern als U32.
Gruß, Jens
P.S.: IDS liefert doch eine Highlevel-LV-Schnittstelle zu µEye-Kameras. Funzt die nicht?
Wer die erhabene Weisheit der Mathematik tadelt, nährt sich von Verwirrung. (Leonardo da Vinci)
!! BITTE !! stellt mir keine Fragen über PM, dafür ist das Forum da - andere haben vielleicht auch Interesse an der Antwort!
Anbei einmal eine kommentierte Version. Für LabVIEW 8.6
Komme derzeit nicht in unser System, um es für eine frühere Version abzuspeichern, tut mir leid. Vielleicht kann ja trotzdem jemand helfen.
Da ist jetzt nicht alles, was ich probiert habe, auf einmal drin. Aber man sieht, wie es funktionieren sollte.
' schrieb:Wenn dll Buffer alloziert, ist das sicherlich nicht schlecht. Dann gibt es keinen Ärger mit dem LV-Speichermanager.
Ja, dachte ich auch. Nur funktioniert die nachfolgende Speicheraktivsetzung damit überaupt nicht (nichtmal mit dem ersten Durchlauf). Ich bekomme offenbar die allokierte Adresse nicht korrekt von dem einen Funktionsaufruf in den anderen. Die Adresse, die aus dem allocate-Aufruf zurückkommt und dann IM Array steht, scheint aber korrekt. Sie wächst bei jedem neuen Aufruf brav um die allokierte Bildgröße. Nur bekomme ich die eben nicht als Zeiger AUF ein Array, sondern als INHALT des Arrays heraus.
Habe alle genannten und andere Formate schon probiert.
Hier würde ich also gern das Umgekehrte erreichen: Daß ich aus dieser lesbaren Bytefolge einen Pointer mache.
Und wie gesagt, zu Debugzwecken aus der Variante "Speicher selbst allokieren per Array" gern den Array-Pointer als Adresse anzeigen. Gibt es da Möglichkeiten in LabVIEW?
Was ich bisher im Forum so gelesen habe, ja wohl nicht? :-(
Mir ist wirklich unbegreiflich, was denn in einer Schleife anders laufen kann, als in hintereinander kopierten Aufrufen. Auch das Arrayinitialisieren habe ich mit in der Schleife drin. Letzteres scheint nichtmal nötig: Wenn ich Kopien der Aufrufe mache, brauche ich sogar das Array nur einmal initialisieren und kann den erhaltenen Pointer mehrfach verwenden - es funktioniert. Also völlig verkehrte Welt...
Der Weg herauszufinden, was der Unterschied zwischen Schleife und Kopie ist, wäre eben, sich den Inhalt der "Drähte" anzugucken, also auch den der Pointer-Drähte. Aus denen bekomme ich aber leider nur den Inhalt des Arrays auf das gepointet wird. :-(
' schrieb:P.S.: IDS liefert doch eine Highlevel-LV-Schnittstelle zu µEye-Kameras. Funzt die nicht?
Ja, was sie liefern sind sehr simple VIs, in denen diese dll-Aufrufe drinstehen. Diese mitgelieferten VIs und auch die Beispielprogramme enden leider genau da, wo es interessant wird: Wenn man die eingelesenen Bilder nämlich als jpg oder gar avi abspeichern will. Dafür gibt es im gesamten paket kein funktionierendes Beispiel.
Da gibt es seiten IDS offenbar keine Lösung für. Und auch in dem "Speicher allokieren"-VI haben sie es nicht mit dem AllocImageMem-Aufruf gemacht, sondern ebenfalls mit per Array selbstallokiertem Speicher. Das fällt auf.
Und es fällt auch auf, daß in dem einen mitgelieferten Beispielprogramm, was einen Ringpuffer von 3 Frames anlegt, es ebenfalls nicht in einer Schleife gemacht wurde, sonder auch das "Speicher allokieren"-VI 3 Mal kopiert.
Insofern bin ich also ganz offensichtlich auf ein Problem gestoßen, das IDS selbst nocht nicht gelöst hat.
Aber ich lasse mich davon nicht abschrecken, solange ich noch Ideen habe, wie ich dem Problem auf die Spur kommen könnte.
Zur Not bestünde noch die Möglichkeit, ein C-Programm (oder wrapper-dll) zu schreiben, das bspw. nur einen AVI-Dateinamen und einen Start-Befehl übergeben bekommt und dann alle auf C-Ebene macht.
In C scheinen sämtliche Aufrufe zu funktionieren, wie die dafür mitgelieferten Sources zeigen.
' schrieb:Ja, was sie liefern sind sehr simple VIs, in denen diese dll-Aufrufe drinstehen. Diese mitgelieferten VIs und auch die Beispielprogramme enden leider genau da, wo es interessant wird:
Die wissen wahrscheinlich warum ... weil es möglicherweise nicht wirklich gut funktionieren wird.
Ich muss ein wenig spekulieren, weil ich diese Schnittstelle nicht genau kenne. Dass das so gar nicht oder nicht so einfach geht, finde ich aber nicht sehr überraschend.
Du übergibst in deiner Schleife bei der zweiten Iteration genau den gleichen Speicher wie beim ersten mal. Um das zu vermeiden ruft das IDS in dem Beispiel mit dem Ringpuffer vermutlich das VI zum Speicherallokieren auch drei mal separat auf, anstatt es in einer Schleife zu machen. Setze doch mal zwischen "Array initialisieren" und "is_SetAllocatedImageMem()" die Funktion "Immer kopieren" (in der Palette Applikationssteuerung, Speicherverwendung). Wenn das nicht funktioniert (was ich mir gut vorstellen kann), dann setze "Array initialisieren" außerhalb der Schleife und mache ein zweidimensionales Array daraus.
Das nächste Problem wird sein, dass die DLL auch nach dem Ende von "is_SetImageMem()" noch auf die Speicherbereiche zugreift. Für LabVIEW wird ein Speicherbereich nicht mehr benötigt, wenn die Leitung endet. Das ist nach "is_SetImageMem()" der Fall. Die Daten werden also (für LabVIEW) nirgendwo mehr gebraucht und können daher auch freigegeben werden. Möglicherweise passiert nur deshalb kein Crash, weil LabVIEW den Speicher nicht frei gibt und ihn stattdessen für evtl. auftretende erneute Aufrufe des VIs reserviert hält. Du müsstest dafür sorgen, dass der Speicher der einzelnen Frames nicht freigegeben und von LabVIEW auch nicht anderweitig verwendet wird. Es könnte leichte Probleme bereiten, LabVIEW hier auszutricksen.
Unter Umständen musst du dich mit Funktion wie GlobalAlloc(), GlobalFree(). des Betriebssystems befassen. Dann hast du das Belegen und Freigeben des Speichers selbst in der Hand. Beispiele für die Anwendung dieser Funktionen müssten sich z.B. in VIs finden, die Daten zwischen dem Clipboard und LabVIEW austauschen.
' schrieb:Du übergibst in deiner Schleife bei der zweiten Iteration genau den gleichen Speicher wie beim ersten mal.
Ja, genau das habe ich ja geahnt, deswegen wollte ich gern mal gucken, was für eine Adresse da übergeben wird.
Wenn das stimmt, dann aber warum? Ich initialisiere doch in jedem Durchlauf ein neues Array!?
' schrieb:Um das zu vermeiden ruft das IDS in dem Beispiel mit dem Ringpuffer vermutlich das VI zum Speicherallokieren auch drei mal separat auf, anstatt es in einer Schleife zu machen. Setze doch mal zwischen "Array initialisieren" und "is_SetAllocatedImageMem()" die Funktion "Immer kopieren" (in der Palette Applikationssteuerung, Speicherverwendung).
Werde ich am Montag einmal probieren.
' schrieb:Wenn das nicht funktioniert (was ich mir gut vorstellen kann), dann setze "Array initialisieren" außerhalb der Schleife und mache ein zweidimensionales Array daraus.
Das hatte ich auch schon probiert. Du meinst, dann das Array mittels "Index-Eingang" (habe jetzt nicht mehr im Kopf, wie das bei LabVIEW genau heißt) übergeben?
' schrieb:Das nächste Problem wird sein, dass die DLL auch nach dem Ende von "is_SetImageMem()" noch auf die Speicherbereiche zugreift. Für LabVIEW wird ein Speicherbereich nicht mehr benötigt, wenn die Leitung endet.
Wäre mir auch klar. Allerdings funktioniert dieses Vorgehen prinzipiell und wurde von IDS in allen möglichen Beispielen und auch von mir schon erfolgreich so umgesetzt.
Heute gab es einen kleinen Durchbruch: Es ist mir gelungen, die dll-interne Speicherallokation erfolgreich durchzuführen. Und erwartungsgemäß funktioniert DIE auch innerhalb einer Schleife. Ich konnte heute erstmal Speicher für 90 Frames allokieren und erfolgreich der DLL in den Ringpuffer hängen. Auch die Videoaufzeichnung in diesen Ringpuffer scheint zu funktionieren. Das war aber auch vorher schon der Fall (wenn es mir denn gelang, ihn "von Hand" zu allokieren.)
Am Montag wird probiert, ob ich die Frames auch auslesen kann.
Dann wäre es möglich, erstmal unsere Kameramessung in den Hauptspeicher zu jubeln (Der müsste dafür reichen, ohne daß etwas in die Auslagerungsdatei geschrieben wird), und nach der Aufnahme in Ruhe ein A VI draus zu machen (was bisher auch immer ein Geschwindigkeitsnadelöhr war).
Sollte meine Lödung sich als wirklich funktionierend herausstellen, werde ich sie natürlich posten.
Ein klein wenig, aber ich denke, es passt hier hin:
Such mal im Forum nach dem Schlagwort MoveBlock, dann stösst du auf Beiträge, die beschreiben, wie du innerhalb von LabVIEW einen Speicherbereich, dessen Anfangsadresse du kennst, umkopierst.
Die Fkt.
is_AllocImageMem (HIDS hf, INT width, INT height, INT bitspixel, char** ppcImgMem, INT* pid)
müsstest du dann als
is_AllocImageMem (HIDS hf, INT width, INT height, INT bitspixel, U32* ppcImgMem, INT* pid) definieren.
Damit ist ppcImgMem die "reale" Anfangsadresse des durch die DLL reservierten Speicherbereichs.
Bei der Fkt.
INT is_AddToSequence (HIDS hf, char* pcImgMem, INT nID)
tust du dann so:
INT is_AddToSequence (HIDS hf, U32 ppcImgMem, INT nID).
Und mit der mehrfach beschriebenen MoveBlock Fkt kannst du den durch die DLL allozierten Buffer nach LV umkopieren.
Müsste (so aus dem Bauch raus) funktionieren.
Und nicht vergessen, durch DLL allozierten Speicher wieder freigeben.
Gruß, Jens
Wer die erhabene Weisheit der Mathematik tadelt, nährt sich von Verwirrung. (Leonardo da Vinci)
!! BITTE !! stellt mir keine Fragen über PM, dafür ist das Forum da - andere haben vielleicht auch Interesse an der Antwort!
' schrieb:Ja, genau das habe ich ja geahnt, deswegen wollte ich gern mal gucken, was für eine Adresse da übergeben wird.
Wenn das stimmt, dann aber warum? Ich initialisiere doch in jedem Durchlauf ein neues Array!?
LabVIEW optimiert das weg. Wozu sollte es aus der Sicht von LabVIEW auch gut sein, bei jedem Schleifendurchlauf erneut den Speichermanager aufzurufen. Die Daten werden ja nicht mehr gebraucht. Der einmal reservierte Speicher kann (an der Stelle) durchaus bei jeder Iteration wiederverwendet werden.
Zitat:Das hatte ich auch schon probiert. Du meinst, dann das Array mittels "Index-Eingang" (habe jetzt nicht mehr im Kopf, wie das bei LabVIEW genau heißt) übergeben?
Ja. Da das, wie du schreibst, auch schon nicht funktioniert, wird mein erster Vorschlag auch nicht funktionieren.
Zitat:Wäre mir auch klar. Allerdings funktioniert dieses Vorgehen prinzipiell und wurde von IDS in allen möglichen Beispielen und auch von mir schon erfolgreich so umgesetzt.
Um es diplomatisch zu formulieren: Sich darauf zu verlassen, dass LabVIEW den Speicher nicht freigibt (was zumindest in der Regel so ist), das ist kein guter Lösungsansatz. Sobald ein Speicherbereich (aus LabVIEW Sicht) nicht mehr benötigt wird, kann LabVIEW damit machen was es will. Es ist nicht sichergestellt, dass das in jeder Situation funktioniert.
Zitat:Heute gab es einen kleinen Durchbruch: Es ist mir gelungen, die dll-interne Speicherallokation erfolgreich durchzuführen.
Na dann: Gratulation und viel Erfolg am Montag.
Bleib bei einer solchen oder ähnlichen Lösung (alles andere ist irgendwie krank). Wo und auf welchem Weg du an den Speicher kommst, das ist ja ziemlich egal. Über die DLL eigenen Funktionen, direkt über das Betriebssystem oder auch durch Aufrufe des LabVIEW Speichermanagers (siehe Hilfe, DSNewPtr(), DSDisposePtr()...).