vugie Posted August 15, 2008 Report Share Posted August 15, 2008 I'm writing wrappers for Open Dynamics Engine, which is open source solver for rigid multibody systems (BTW, anyone interested in it?). It has very clean and well documented C API (although it is written in C++) and does not require to write any additional DLL wrapper. With one exception. It uses quite unusual way to retrieve values of forces in particular constrains. For each constrain you want to retrieve force during simulation, you have to allocate defined structure (6 floats) and pass its pointer to special function before the simulation. During simulation loop values in allocated structures are updated automaticly and there is no function to read them (what for it would be if you program in C...). But how to to it with LV? One idea I have is to create additional DLL with 3 functions: 1st allocates memory for the structure (or even for given number of bytes to make it more universal) and returns a pointer, 2nd reads from the pointer and return value (or string to be casted to whatever you want) and 3rd deallocates memory. Simple but ugly and leads to memory leaks if LV wrappers user won't care to deallocate memory. Are there any other ways to to this? Another point, but less important. ODE provides simple but convienient functions for 3D visualisations (rather for debug purposes). But it works using callback - you have to pass a function with main simulation loop, so making any DLL wrapper for that (until it is not LV DLL) does not make sense because all LV wrappers become unusable. Anything changed with that in 8.6? I mean is it possible in any way to directly pass a strictly typed VI as callback function? Quote Link to comment
ragglefrock Posted August 15, 2008 Report Share Posted August 15, 2008 QUOTE (vugie @ Aug 14 2008, 04:02 AM) I'm writing wrappers for Open Dynamics Engine, which is open source solver for rigid multibody systems (BTW, anyone interested in it?). It has very clean and well documented C API (although it is written in C++) and does not require to write any additional DLL wrapper. With one exception. It uses quite unusual way to retrieve values of forces in particular constrains. For each constrain you want to retrieve force during simulation, you have to allocate defined structure (6 floats) and pass its pointer to special function before the simulation. During simulation loop values in allocated structures are updated automaticly and there is no function to read them (what for it would be if you program in C...). But how to to it with LV?One idea I have is to create additional DLL with 3 functions: 1st allocates memory for the structure (or even for given number of bytes to make it more universal) and returns a pointer, 2nd reads from the pointer and return value (or string to be casted to whatever you want) and 3rd deallocates memory. Simple but ugly and leads to memory leaks if LV wrappers user won't care to deallocate memory. Are there any other ways to to this? I am not sure there's a safe way to pass a pointer to LabVIEW-allocated data and have it be continuously updated after the original function call completes. LabVIEW might think the memory is not being used anymore and deallocate it or overwrite it. So I believe you might have to write at least one wrapper function to do a malloc for the struct type and return a pointer to the memory. After that, you won't need any additional functions to simply read the value. LabVIEW has a built-in function in LabVIEW.exe called MoveBlock. You call it much like a DLL function in the Call Library Function Node, except you type in LabVIEW instead of a DLL name. MoveBlock can copy from a source location (the malloc'd struct from the simulation) to a target location (a LabVIEW cluster with 6 doubles). See chapter 6 of this PDF for more info on the function prototype for MoveBlock. There's possibly also an appropriate function that resembles malloc that you can call directly from LabVIEW to avoid needing a wrapper DLL at all. Check out AZNewPtr for instance. If I understand the second problem correctly, you need to get a function pointer to a VI to pass to the simulation DLL. This is rather tricky, but someone found a roundabout way to do this using LabVIEW's .NET callback functionality. Check out the solution here. Quote Link to comment
vugie Posted August 30, 2008 Author Report Share Posted August 30, 2008 Thank you for the answer QUOTE (ragglefrock @ Aug 14 2008, 03:28 PM) LabVIEW has a built-in function in LabVIEW.exe called MoveBlock. You call it much like a DLL function in the Call Library Function Node, except you type in LabVIEW instead of a DLL name. MoveBlock can copy from a source location (the malloc'd struct from the simulation) to a target location (a LabVIEW cluster with 6 doubles). See chapter 6 of this PDF for more info on the function prototype for MoveBlock. There's possibly also an appropriate function that resembles malloc that you can call directly from LabVIEW to avoid needing a wrapper DLL at all. Check out AZNewPtr for instance. I didn't play arount much with these functions, but such solution seems to work. But how it will look like with built application running with runtime engine only? QUOTE If I understand the second problem correctly, you need to get a function pointer to a VI to pass to the simulation DLL. This is rather tricky, but someone found a roundabout way to do this using LabVIEW's .NET callback functionality. Check out the solution here. I knew this article and I tried to reproduce this functionality some time ago but without success (I had problems with compiler as I'm totally not familiar with NET environment). However, I wasn't strongly determined to do that... I have another issue around this subject: ODE is designed to let to compile it either for single or double precision computations. It simply uses some macros to set input parameters for ALL (400+) functions to float or double. I would like to reproduce such design in my wrappers. All type definitions I use I built using abstract type Real which holds now Single type. So changing this type to Double obviously updates all other types. But for CEF Node I have to uniquly determine numeric input type. As most parameters are passed as values I can't use Adapt to Type which passes only pointers. Have I to use Conditional Disable Structure? I discovered some time ago that extensive use of disable structures decreases performace. And beside that when I wire to certain function parameter from my Real type I get coercion dot even when parameter type and type inside Real agrees. I understand why it appears, but will it influence on performance? What approach should I choose to be able to be able to bulid my library for either single or double precision? Another point. Most functions in ODE as first argument uses ID of something (world, body, joint, etc.) it operates on. It's simply a pointer to proper structure. I currently use UInt32 to handle it. But what if the DLL will be compiled for 64-bit architecture? Maybe should I use Int64 from the start? Will then 32-bit DLL behave properly? Quote Link to comment
ragglefrock Posted September 3, 2008 Report Share Posted September 3, 2008 QUOTE (vugie @ Aug 29 2008, 03:37 AM) Another point. Most functions in ODE as first argument uses ID of something (world, body, joint, etc.) it operates on. It's simply a pointer to proper structure. I currently use UInt32 to handle it. But what if the DLL will be compiled for 64-bit architecture? Maybe should I use Int64 from the start? Will then 32-bit DLL behave properly? LabVIEW 8.6 has a small new feature that allows CLFNs to specify an input parameter to be a pointer-sized integer. LabVIEW will adapt the data to fit the pointer size for the operating system currently being used (32 or 64-bit). The idea, I believe, is to always use an I64 or a U64 for the pointer data, and then let LabVIEW decide whether to only use 32 bits of that data or the whole item. If you can't use LV 8.6, you'll probably have to use Conditional Disable Structures to configure separate calls for 32 or 64 bit systems. Or you can write a wrapper DLL to do the same type of data management. Can't think of a great option for switching between Single or Double floating point numbers. Your ideas seem to be as good as any I can think of right now, unfortunately. http://digital.ni.com/manuals.nsf/websearch/1CEFD3AEAB830B3886257451006BD8BD' target="_blank">Link for LV 8.6 release notes. Pointer-sized integer feature is page 45. Quote Link to comment
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.