LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

PICAM SDK, Call Library Function, crashes LV

Solved!
Go to solution

Hmm, making a DLL does not look like rocket science, I will try to follow this guide tomorrow:

https://www.zealfortechnology.com/2013/08/create-c-program-dynamic-link-library-dll-visual-studio-20...

 

If I succeed, I will wrap some other functions too from the PICam SDK, so the LabVIEW CLNs will be more simple...

0 Kudos
Message 21 of 89
(2,042 Views)
Solution
Accepted by topic author Blokk

@Blokk wrote:

 

EDIT: for sure I am doing it wrong, since I cannot give a LabVIEW array to the DLL, since in C arrays are fixed sized. I guess I need to use again MoveBlock functions with CLN, I just having difficulty to figure out exactly how 🙂 I also found this: https://lavag.org/topic/16106-managing-structures-with-array-of-structures-as-dll-input-parameter/

No in C arrays don't have to be fixed size. They are if you have following syntax:

 

datatype variable_name[fixed_size];

but you have a pointer:

PicamRoi* roi_array;

This means that you need to create a structure (cluster) with first a 32 bit integer (32 bit LabVIEW and DLL) or a 64-bit integer (64 bit LabVIEW and DLL) followed by the 32-bit integer for the roi_count. Then you have to allocate a memory area that is large enough to contain roi_count * PicamRoi elements, get the pointer from that and store it in the first element of above cluster.

Then we also need to copy the ROI parameters into that pointer before calling the DLL function.

 

PICAM Set ROI.png

 

And yes I would change the handle to an uInt64 value in the LabVIEW diagram and change the Call Library Nodes to Pointer sized unsigned Integer!

Rolf Kalbermatter  My Blog
DEMO, Electronic and Mechanical Support department, room 36.LB00.390
Message 22 of 89
(2,041 Views)

Thanks for your help! I really appreciate it! I will test the VI tomorrow morning.

0 Kudos
Message 23 of 89
(2,035 Views)

rolfk wrote:

 

And yes I would change the handle to an uInt64 value in the LabVIEW diagram and change the Call Library Nodes to Pointer sized unsigned Integer!


Can you elaborate this part? I think I got the rest, but why should we change the U32 into U64 for the camera handle parameters? It is defined as 32 bit unsigned integer in the SDK, so we should use U32, no?

Thanks! 🙂

0 Kudos
Message 24 of 89
(2,028 Views)

From the picam.h header file I see this definition:

 

typedef void* PicamHandle;

This means that this parameter is a void pointer. So it is a pointer to something and as such it needs to be 32-bit for 32-bit LabVIEW and 64-bit for 64-bit LabVIEW. 

 

I'm not sure where you saw that it would need to be a 32-bit unsigned integer.

 

And yes you may think that you currently only use 32-bit anyways (and the SDK is maybe only available as 32-bit version) but the only reason to not treat this right from the beginning anyways is if you happen to need to run this library in older versions of LabVIEW than 2009. There the pointer sized integer is not an option for the Call Library Node, since those LabVIEW versions never supported 64-bit executables anyhow.

Rolf Kalbermatter  My Blog
DEMO, Electronic and Mechanical Support department, room 36.LB00.390
Message 25 of 89
(2,024 Views)

Rolf,

I just tested your ROI VI (implemented into my project), and it works! 🙂 The PICam dll CLN was crashing the IDE, but then I realized its "Calling convention" setting was left as "C". Changing it back to "stdcall" fixed this issue (all of my CLNs are set for "stdcall", the setting "C" results in imminent IDE crash).

 

I also fixed the "cam handler" parameters, set them to be U64, and also specified them as "Pointer sized unsigned Integer" in the Call Library Node terminals!

 

I try to digest carefully your explanations, and how these MoveBlock functions can be handled to play with these more complicated C structs, I learned just a lot from a single thread 🙂

One more question, regarding to how to avoid possible memory leak. So, if I specify a ROI setting to my camera (using your method with MoveBlock + ), after that I call a function "Commit settings to Cam", so my camera starts to use the new settings. All fine. However, in the manual, there is also a function called 

 

Picam_DestroyRois (const PicamRois* rois);

Description from the manual:

 

Picam_DestroyRois() releases memory that has been allocated by PICam for use by the array rois. If rois is null, calling Picam_DestroyRois() has no effect.

 

Question: in your ROI.vi example we dispose the pointer pointing to the ROIs array memory location. In this case, do I need to use the above mentioned "DestroyRois() function", or not? If I do need it, what is the best way to do it?

 

Rolf, thanks again for your huge help, the camera lvlib is practically finished! If your way leads to Karlsruhe in the future, just pm me, I own you some beer! 🙂

 

ps.: i attach my modified VI in v2014

0 Kudos
Message 26 of 89
(2,020 Views)

Blokk wrote: 

 

Picam_DestroyRois (const PicamRois* rois);

Description from the manual:

 

Picam_DestroyRois() releases memory that has been allocated by PICam for use by the array rois. If rois is null, calling Picam_DestroyRois() has no effect.

 

Question: in your ROI.vi example we dispose the pointer pointing to the ROIs array memory location. In this case, do I need to use the above mentioned "DestroyRois() function", or not? If I do need it, what is the best way to do it?


Unlike in managed environments where you have a common guaranteed memory allocator, this is not true in C (and C++). The memory allocator in your Picam DLL could be a completely different one than what LabVIEW is using, even if both underneath use malloc() and free(). That is because the used C runtime library may or may not directly pass those calls to the underlaying system allocator and instead usually implement their own memory allocation scheme, requesting large memory blocks from the OS and handing them in smaller pieces to the application in question.

But Unless you use the same C compiler and version for the calling application and any used DLL, the underlaying C runtime library is generally different. This means that whoever created a block of memory ultimately needs to deallocate it in the end. 

 

Now for Picam_SetParameterRoisValue() the ROI parameter is simply passed as a pointer to the actual structure. Since the caller knows how big the array needs to be and therefore can decide how big the memory allocation needs to be, he is responsible for creating it and after the call deallocating it. But for Picam_GetParameterRoisValue() the caller has no idea how big the memory block needs to be. There are three possible solutions to that.

1) Call the function first with a NULL pointer and the function returns in some other parameter the needed amount of array elements.

2) The documentation states that the function needs to preallocate a certain buffer and pass it in and if the caller forgets that or creates a to small buffer very bad things happen.

3) The funciton allocates whatever memory is needed and returns that to the caller but since the caller can't deallocate it with its own memory allocator the library also needs to provide a function to deallocate this memory with its own memory allocator.

 

Lets look at the two functions:

PICAM_API Picam_GetParameterRoisValue(
    PicamHandle camera,
    PicamParameter parameter, 
    const PicamRois** value ); /* ALLOCATES */

PICAM_API Picam_SetParameterRoisValue(
    PicamHandle camera,
    PicamParameter parameter,
    const PicamRois* value );

You can determine from the look of the function prototype with a double pointer return value for the ROIs value, the ALLOCATES remark behind the function and the fact that there is a specific deallocator API that the library developer chose option 3) for the Get function.

No such thing is true for the Set function. First the caller has to allocate the buffer in order to pass it to the function because only the caller knows how big the buffer needs to be, and second there is no way the function could return an allocated buffer through a single pointer parameter anyways. Since the caller allocated the memory buffer he is responsible for deallocating it and the Picam_DestroyRois() function has no business to try to do something with this buffer.

 

 

Rolf Kalbermatter  My Blog
DEMO, Electronic and Mechanical Support department, room 36.LB00.390
Message 27 of 89
(2,016 Views)

Very nice and detailed explanation!

Anyway, I try to follow a pragmatic approach for this project. Namely, I only implement the minimum base of functions we need for our application.

For example, I decided I am not going to use the Picam_GetParameterRoisValue() function, so I do not have to deal with its memory allocations. The reasons is that, we will always use a single ROI set for our CCD, and we know what we specify. Also, we can request other info, like the "FrameSize", which reports about the actual total number of pixels. There are also the functions like "SensorActiveWidth" which I think reports abut the actual active ROI sizing.

 

So the only function I will use is the "Picam_SetParameterRoisValue() ", using your implementation. As I understood from your reply, I do not need further memory deallocation in this case, since we dispose the pointer to the ROI array inside the VI.

0 Kudos
Message 28 of 89
(2,010 Views)

@Blokk wrote:

 


So the only function I will use is the "Picam_SetParameterRoisValue() ", using your implementation. As I understood from your reply, I do not need further memory deallocation in this case, since we dispose the pointer to the ROI array inside the VI.


That is completely correct!

Rolf Kalbermatter  My Blog
DEMO, Electronic and Mechanical Support department, room 36.LB00.390
0 Kudos
Message 29 of 89
(2,007 Views)

Rolf,

I tried to use what I have learned about usage of MoveBlocks from you, but it looks like I am a very bad student! 🙂

The very last function missing to be implemented, to acquire pixel data from the camera. This one:

Picam_Acquire
(
    PicamHandle                 camera,
    pi64s                       readout_count,
    piint                       readout_time_out,
    PicamAvailableData*         available,
    PicamAcquisitionErrorsMask* errors
 );
typedef struct PicamAvailableData
{
    void* initial_readout;
    pi64s readout_count;
}

I tried to use the logic what was used in some other VIs, but I am still crashing my LV IDE, so I do something (or several things) wrong! 🙂

Here is a snippet, and I also attached the VI I use. The data structure explanation (Readout formatting) is in the manual, page 148.

Million thanks! 🙂

 

PICam.lvlib_Acquire_CCD_data_BD.png

0 Kudos
Message 30 of 89
(1,997 Views)