I'm trying to receive data from a device with a dll. I implemented the manufacturer's dll using the Call Library Function Nodes and got several subvis. I guess the setting is pretty similar to the issue described here: How-to-use-buffer-from-a-3rd-party-dll , but I can't find a solution for my program.
This is my actual program:
The sequences work as follows:
1. connect device
2. Add sensor and define buffer: Here I have to provide the device with a buffer into which the data is to be written. This is an array with entries of the type int32. The buffer is divided into equal blocks, whose number and size is also defined. So I have to create a buffer for the data by passing an array of the desired size to the dll function. The buffer is large enough to hold all the data that will be collected during the streaming session.
The C-Syntax for this input is: VLD_addSensor(... int32_t *buffer, ...)
Unfortunately I just can define the size of the array, that has to be filled in the buffer (as shown above), but I can't give in a pointer to the part of the memory, where the array will be filled. When I try to define a pointer and connect this to the entry of my addSensor.vi (I changed the parameters from Array to numeric Pointer to Value in the CLFN) LabView crashes without any error message.
3. Initiate Readout and wait 1 second to fil the buffer. The wait.vi in this sequence is necessary to have enough data inside of the buffer.
4. Read buffer: This vi gives out a pointer to the starting address of the array from where I want to read the block size entries.
The C-Syntax is for the Pointer to buffer output is: VLD_readSensor(...int32_t **data,...)
I used MoveBlock to dereference the pointer to a single value, as shown above and described here: Dereferencing-Pointers-from-C-C-DLLs-in-LabVIEW
When I run the vi the output parameter "Data" from MoveBlock is the same value like the pointer "Pointer to Buffer", so I guess MoveBlock doesn't work properly.
I also tried to directly dereference the array with MoveBlock, but then I either get no value for the output of MoveBlock or the error message "Access violation (0xC0000005) bei EIP=0x00007FFB951F85C7" when the input parameter for Size is too big.
5. Drain the buffer, stop readout and disconnect the device. This leads to no problems.
So in conclusion I guess the problem is that I define an array for the buffer in step 2, but no pointer to the location, so there are problems with reading out the buffer in step 4.
Does anyone have a good idea to solve the issue? I attach the vi, the dll and the related header file.
Solved! Go to Solution.
This is not how C memory management works!!
The DSNewPtr() call is correct, but there is no use in adding the MoveBlock() call afterwards to write data into.If you really need to guarantee that that memory buffer contains all 0 values you should instead simply use the DSNewPClr() function.
This 64-bit integer IS the pointer. So to pass it to your Call Library Node you need to configure that parameter as Pointer Sized Integer, Pass by Value.
Then comes the reading. What a terrible DLL API they designed! I suppose the pointer that is returned from the VLD_readSensor() function is the same as was passed in to the VLD_addSensor() function. Otherwise everything I'm saying now is off for sure.
You can use that pointer (configure it as Pointer Sized Integer, Passed by Reference. Then you have to use the MoveBlock() function to copy the data from the pointer into a LabVIEW array. Preallocate that array to the correct size before you pass it to the second parameter of MoveBlock() configured as Array Data Pointer, int32. The first parameter for MoveBlock() is a Pointer Sized Integer, Passed by Value and receives the pointer, either the original pointer from the DSNewPClr() call or the one received from the VLD_readSensor(). They better be the same or things are going quickly bad!
The third parameter is a Pointer Sized Signed Integer, Passed by Value. This receives the number of bytes to copy which should be 4 times the size of the array connected to the second parameter and the same as the size used for DSNewPClr().
thank you for your reply, I was hoping that you will read this.
I added the first MoveBlock to define the size of the array since the dll needs a large block that it can use as buffer. But from your reply I guess it's enough to set the size for the buffer at the size-input of DSNewPClr? As the size I chose the product from block size and the number of blocks which is the minimum size of the array according to the manufacturer.
I wired the return parameter of DSNewPClr (a Pointer Sized Integer) to the buffer-input of VLD_addSensor and set the parameter to Pointer Sized Integer, Passed by Reference. The parameters of the Data-Output from VLD_readSensor I set in the same way.
Afterwards I set MoveBlock as you described:
First parameter as Pointer Sized Integer, Passed by Value and input for the pointer I got from the data output from VLD_readSensor.
Second parameter as Array Data Pointer, int32 with the dimensions of the array as input and the desired array as output.
Third parameter as Pointer Sized Signed Integer, Passed by Value with the array dimensions times 4 a input. (Why should it be 4 times the size of the size of the array?)
Unfortunately I can't check whether the pointer I created and the pointer that comes from VLD_readSensor are the same since I get either an Access violation (0xC0000005) (when running the vi in highlighted mode) or an Unknown (0x00000000) error message as soon as the fourth sequence starts.
Does this error appears because of probably different pointers inserted from DSNewPClr and output by VLD_readSensor?
You find my vi attached.
Please backsave your VIs to LabVIEW 2018, that lets me view them without having to launch a separate Virtual Machine with the 2020 LabVIEW, which at the moment has an installation problem.
Rolf, it works now! It's enough to define the size of the buffer with initialising the array for VLD_addSensor. I guess the initial problem were wrong datatypes in the CLFNs, especially for the data pointer in VLD_readSensor. So, thank you very much for your help.
Could you still explain me why the size of MoveBlock has to be 4 times the array size?
I have been checking the header file and I believe that you should only try to read 128 samples, the block size defined in the add_sensor() call, from the pointer returned by the readSensor() function. The comments in the header file for the readSensor() function make me believe that only one blocksize of data is supposed to be returned from the readSensor() function (most likely it advances the pointer into the passed in buffer by this amount on each readSensor() call.
Instead of adding that two second delay in parallel with the startReadout() call, you should also be able to insert the fillSensorBuffers() call instead.
Also the VIs as provided are a mess. I did edit some of them to make them more LabVIEW user friendly. I did NOT go through all of them but only the ones used in your VI. With proper error and device handle chaining you also won't need any sequence structure anymore!
All VIs should have an error cluster in and out and properly propagating errors through! It would be useful to edit the other VIs accordingly too!
The factor 4 is necessary since the size parameter to MoveBlock() is in bytes, but the array data you try to copy into is an array of int32. Each int32 occupies 4 bytes.
Yes, the manufacturer also recomments a the blocksize of at least 128 samples to react as fast as possible to the data.
readSensor returns all blocks of the buffer that are already filled, so I really have to think about another soultion than the time delay, this was only a first shot.
Thank you for modifying the other VIs and again thank you for your help.
unfortunately the vi still doesn't work perfectly. I expanded the vi to record the data continiously.The subVIs VLD_readSensor and VLD_releaseMemory are in a while-loop now.
Now the curious issue:
I have to run the first part before the while-loop in Highlighted Execution or insert the time delay (I guess to fill the buffer), otherwise this would cause an Error 1097. Afterwards the while-loop iterates, but VLD_readSensor only releases one block of the array and gives the internal error, that there is not enough data to fill a hole block and VLD_releaseMemory states that there is no unreleased memory. The data is still plotted, and now LabView error occurs.
When I stop the VI and start it again (without closing it) and now without Highlighted Execution or the time delay it works.
From time to time it also stops reading data from the buffer and the subVIs state again the above mentioned errors, but the while loop still runs.
I couldn't see any pattern here when the issue occurs, but this issue also happens when I just highlight one of the numeric controls. That's really weird. Could it be a problem with LabView memory?
I will add a screenshot and the current vi.