I am trying to collect some data from a 3rd party scope (Picoscope) and am having some buffer issues. I communicate with the scope using a dll which is called using Call library function nodes. I am trying to stream data from the scope. To get this data, the following procedure is used:
1) Send commands to set up scope vertical channels, timing, and triggering.
2) Create a buffer for the data by passing an array of the desired size to a dll function. The buffer is large enough to hold all the data that will be collected during the streaming session.
3) Send a command to start data capture.
4) Send a command for the dll to put available data in the buffer and get the location and length of the next data.
5) Read the data from the specified location in the buffer.
6) Repeat 4 and 5 until done.
7) Stop data capture.
The dll is using a buffer to pass data to LabView. As I understand it, the buffer is the actual part of memory that holds the array that is passed to the dll in step 2). The data is read (step 5) by using an Array subset node. For this to work, the wire passed to the Array subset node must use the same location in memory as the array passed to the dll in step 2. It seems that what is going on here is different than how things normally work with LabView data flow. A buffer is created and data is carried along a wire, but the dll reaches in and changes the data on the wire while it is flight. This works in simple code where the buffer wire passes fairly directly from step 2 to step 5 without being copied. I am running into trouble in my code, where steps 2 and 5 are encapsulated in different subVIs, some of which are dynamically dispatched.
I would be grateful to be pointed to any documentation about how to work with buffers such as this. It seems like to be able to read the data, I must be able to access the same location in memory that was used to create the buffer initially. How do I ensure that LabView doesn't reallocate this memory while the data capture is going on? How can I be sure that I am accessing the same memory location when I use the Array subset node?
Solved! Go to Solution.
The Picoscope driver is terribly abusing the fact that LabVIEW arrays are for performance reasons not relocated as long as they are kept inside a VI. That of course totally breaks apart once you try to seperate the individual steps into different VIs.
The only way to get around that is by proper C style memory management. You have to allocate all those buffers explicitedly and pass their pointers around and at the end after the acquisition is done copy the contents from that buffer into a LabVIEW array to use its data in LabVIEW. Also don't forget to dellocate each buffer properly after it was used.
This does have performance consequences as you will need to add an extra copy from the created buffer to the LabVIEW data but that is how things are. You can't take over LabVIEW data arrays asynchronously beyond the duration of a Call Library Node call. There is a possibility to use external Data Value References for such purposes but that is very advanced C programming (and yes it requires the external DLL to do much of the work, there is no way to wrap a DLL like the one from Pycoscipe in LabVIEW to do this. The DLL has to do most of the work directly and by calling semi-documented LabVIEW functions.
Thank you for your response Rolf. You seem to be confirming a couple of fears that I had: the Picoscope driver is using a side effect of how LabView manages memory and as a result, I can't really depend on this working as I get further away from where the buffer was originally created or perhaps even in future versions of LabView 😞
Your advice about C style memory management suggests to me that I should write a dll with functions to allocate the buffers and read the data from them. The pointer to the buffer created by my dll would be passed to the Picoscope dll, my dll would read the buffer, and LabView would then get the data from my dll. Does this sound like what you meant? This will be a stretch of my skills since I do very little C programming, but should be doable (I have a C guru in the office).
I was sort of hoping that there was a way that LabView could allocate a buffer and supply a pointer to it (or something equivalent). I actually tried using a DVR to deal with this issue, but had some problems. I was thinking that the DVR would make the memory allocation stick so the dll can continue to put data in and let me access the same memory later on to read the data. It worked fine when I was only reading one channel from the scope, but I ran into trouble when I started reading multiple channels. Each channel needs its own buffer, which was handled using a FOR loop. An array was created, the array was passed to the dll so it knew where to buffer the data, and the DVR for the array were created inside the FOR loop (one iteration per channel). I'm not sure if the DVR was using the memory from the original array, or a copy of that memory. It's also unclear to me whether the buffer arrays that were created in each iteration of the loop utilized different memory from one another or if LabView just reused the memory from the previous loop iteration.
Writing a wrapper DLL is of course one possibility. Another one is the use of the VIs under
DSNewPtr.vi allocates a memory buffer that you have later to deallocate with DSDisposePtr.
You then have to program one more Call Library Node to call the LabVIEW MoveBlock function to copy the data from the pointer into a LabVIEW array to use further in LabVIEW.
Okay, I'm trying to use DSNewPtr, MoveBlock, and DSDisposePtr to solve the buffering problem that was described above. I will create a pointer to a large buffer and pass that to the Picoscope dll. A function in the dll gives me the position and length of the latest data it has added to the buffer and I will use MoveBlock to move data from that portion of the buffer into a LabView array. I am not very familiar with the LabView memory manager functions, so I have been trying to use them in some simple code before I integrate them into my application. As shown in the attached code snippet, I create a pointer and a LabView array, I then Use BlockMove to move the contents of the array into the memory that was just allocated with DSNewPtr. I then try to copy some or all of that data out of the allocated memory block to another LabView array. This works ... sometimes.
1. I copy 5 elements into the memory block and then back out (Index of first element to move = 0, Number of elements to move = 5) - > everything is good.
2. I copy 5 elements into the memory block and then copy 1 element out (Index of first element to move = 2, Number of elements to move = 1) - > LabView crashes. The crash may not happen until the VI is closed.
Any thoughts about what I'm doing wrong?
The problem is in the DSDisposePtr call. You have to pass the pointer allocated with DSNewPtr.
a = DSNewPtr(size);
What you do is:
a = DSNewPtr(size);