08-29-2012 06:14 AM
Hi,
I am a student currently doing an internship, and I may need some help. First of all, I am a beginner with LabVIEW, so maybe what I am asking is silly but I am completly lost.
In my project, I have to command a CD/DVD reader manually (speed of rotation, data transmitted...), and for this I am using a free DLL file I find download on this website.
So I do not have access to the source code, just to the header file and the DLL. When I am calling it, I get the error number 1097.
As I understand in several posts on this forum, the reason is probably that the buffer used by the Call Library Node is not correctly sized. Indeed, the parameter is a pointer to a cluster that contains numbers and strings. But how exactly can I do a allocation of memory on Labview?
Also, I understand that writting a C++ wrapper could be a solution, but can I do that whithout the source code? (I only know a little bit about C and not about C++, but I understand that both are similar so I hope I will manage to do it if you think it is possible. Still if it is, could anybody send me some documentation about it).
If anybody could have any idea that would be useful or at least could advise me some documentations, I would me more than grateful.
The header file and the DLL files are available on the link I post (it is not my work so I am a little uncomfortable posting it here)
Thanks a millions,
08-29-2012 06:39 AM - edited 08-29-2012 06:47 AM
It seems you are trying to interface WinASPI API directly. It has been a very long time when I checked into this (more than 10 years) but ASPI definitely is NOT an API that you want to interface to directly from the LabVIEW Call Library Node. An intermediate DLL written in C is almost the only feasable and for the long run maintainable solution. This intermediate DLL mediates between the ASPI API and a more LabVIEW friendly API that can be much easier interfaced from the Call Library Node.
If you insist on going this (IMHO fruitless) path you will need to provide much more information such as your VIs you have done so far, the API function declarations you try to interface to, together with all other declarations that might be used in there, and aren't standard WinAPI declarations. The chances that someone has tried to do the same as you did, is minimal and in that case the information you have provided so far is virtually useless as nobody is going further than clicking on your link, and it is unlikely anyone knows that this is in fact about WinASPI and even much more unlikely that someone will bother to dig up all the technical details across the web to understand what the complications might be. Even in the unlikely case someone does, there is no starting point in helping you since there is simply no information as to what you have tried so far and how, and where it might be really going wrong.
Writing a wrapper has nothing to do about knowing the source of the DLL you wrap, although it never hurts if you have that source available to check into particular implementation details. But if you use a C compiler to create a wrapper DLL and hand it the correct header files for your APIs you interface, this C compiler can handle some of the things that you must deal yourself manually when trying to configure the Call Library Node correctly. And it forces you more strictly to think about things like proper memory allocation and deallocation, things you have to do in LabVIEW as well when interfacing to C functions, but which often can get forgotten, since everythign else in LabVIEW is so automatic when it concerns memory management.
09-10-2012 09:44 AM
Hi,
First of all, thanks for your answer. Sorry for answering just now, but I was trying to advance by my own too, and also I was asked to work on other things in my internship. I will try to explain you what I have done so far.
Thanks for explaining me the difference between an API and an ASPI, I have to recognize that I did not get the difference between both before you told me, and that makes everythink clearer to me now. Still, the "dll" I find on this website seems to be a ASPI Manager, and they say
"The ASPI Manager for the SCSI host adapter processes these function calls and generates the appropriate SCSI commands to the SCSI peripherals".
So, maybe I misunderstand that again, but it seems to me that the first step you recommend to do is already done by the creater of this DLL.
Also, I am now using Labview 2011 instead of 2010, but I don't think this change a lot in my problem. I send the labview code I made, it is currently very basic but if I cannot access the basic function of the DLL, there is just no point trying to make a code more complicated. I am for now just trying to call one of the function of the DLL and see what is happening.
For this first function, the parameter to send to the node is a pointer on this structure:
typedef struct
{
BYTE SRB_Cmd; // ASPI command code = SC_HA_INQUIRY
BYTE SRB_Status; // ASPI command status byte
BYTE SRB_HaId; // ASPI host adapter number
BYTE SRB_Flags; // Reserved, MUST = 0
DWORD SRB_Hdr_Rsvd; // Reserved, MUST = 0
BYTE HA_Count; // Number of host adapters present
BYTE HA_SCSI_ID; // SCSI ID of host adapter
BYTE HA_ManagerId[16]; // String describing the manager
BYTE HA_Identifier[16]; // String describing the host adapter
BYTE HA_Unique[16]; // Host Adapter Unique parameters
WORD HA_Rsvd1; // Reserved, MUST = 0
}
SRB_HAInquiry, *PSRB_HAInquiry;
It is not really working so as I read on this NI webpage: http://digital.ni.com/public.nsf/allkb/DCB90714981A1F148625731E00797C33
"Note that if your complex data type is a struct with more than primitive data types (int, double, char), it is easiest to create a wrapper DLL from a C-based language."
So this is what I have been trying to do, and maybe it is very basic, but if anyone could send me a link on how to create a wrapper DLL, it would be very useful. I already download the one National Instrument made, but I did not really understand it.
The DLL seems to work fine as I manage to call it from a C console programme. (I send the code too). But I tried to followed some tutorials but I just cannot create a DLL that I could use, so maybe there is something badly set in my IDE (I am using Code::Blocks). So if anybody has any idea of what is going on I would be very grateful. Again, the DLL I tried to make is very basic but if the basic are not ok, there is no point going further.
This is what is happening right now : I create the dll file following the instruction but when I compile I get this warning:
"warning: 'int addition(int, int)' redeclared without dllimport attribute: previous dllimport ignored"
and then I just can't compile the test programm because I get the error: altough I did set the file.a as a linker.
"undefined reference to `_imp__addition' "
I send the compressed files that I made, I think there should be everything that is needed to answer me, except the DLL file that is available here http://www.frogaspi.org/download.htm
Again sorry, but the owner of this library explicitly asked not to purpose a local download so I feel very unconfortable doing that, so please, just click on the link and download it from there.
I do not know if anybody has ever done what I am trying to do, and I am not asking for someone to do it instead of me, I am sorry if I sound like it in my previous message, this was definitly not my intention.
Still, the problem of having to write a wrapper seems to be a commun issue for people calling DLL in Labview, and I didn't find answer very clear on how to create a dll. I guess I could eventually find out by myself, but if anybody can help, that would make me save a lot of time.
Maybe what I am asking is very easy, but again my knowledge about C language is basic, I am not a computer science student so...
Anyway, thank in advance,
Adrien
09-10-2012 12:36 PM
Well the WinASPI API is indeed a DLL wrapper to device specific APIs but don't let the word wrapper mislead you here. There are wrappers and wrappers. WinASPI is a so called manager wrapper that provides a common API to application to deal with any SCSI device or SCSI like device (it can also access IDE devices through the Windows API if done right, since IDE is simply a low cost way of SCSI device with a much lower level hardware interface exposed by the peripheral in order to save some logic circuitry on every peripheral. That was an important cost saving at a time, FPGA and such didn't even exist and you had to make custom mask semiconductors for anything integrated.
Now a wrapper for LabVIEW use is a different thing. It basically just exposes functions that have parameters that are easier to interface with the Call Library Node. C allows for arbitrarly complex parameter types. If the LabVIEW Call Library Node would support all variations and incarnation of what you can do in C, the configuration dialog would get extremely complex to the point were nobody but a professional C prgrammer could understand it anyways. It doesn't mean that you can't interface to more complex parameter types but you have to do sometimes pretty low level C stuff, that are at least partly taken care of by the C compiler if you program that API call in C. Other things like memory allocations and such have to be done in either case explicitedly but it is a standard thing for a C programmer to have to do that explicitedly and a very rare thing to do for a LabVIEW programmer on the other hand. So it is a steep learning curve for the average LabVIEW programmer.
Now the API you show as example isn't even one of the more complex variants to interface. However you make the standard error of mistaking fixed size arrays in a struct as being the same as array pointers. That is truely wrong, as a fixed size array gets always inlined in a structure by any C compiler, so it is in fact more synonymous to a LabVIEW cluster of that many elements embedded inside the outer cluster. This is since LabVIEW doesn't know fixed size arrays and even if it did it is not clear that it would use the same inlining as is common in C. And if the structure contains real array (or string) pointers you still couldn't just assign LabVIEW arrays to that cluster element. A LabVIEW array is always a pointer to a pointer to a data structure that contains both the number of elements in the array as well as the array data. A C array only is a pointer to the array data without any explicit size indication. This makes passing arrays to C functions also very error prone for buffer overflows unless the API designer takes a lot of care to use extra parameters that give the function information about the size of the array. And to make things even more complex there is something called alignement. This means that a C compiler usually aligns every element in a cluster to the smaller of either its inherent memory size or a default alignment. And Windows DLLs usually use a default alignment of 8 so a double would be always aligned to an address that is a multiple of 8, and int32 bit to an address that is a multiple of 4 and so on. LabVIEW uses on Windows 32 Bit a default alighment of 1 meaning it packs data as tightly as possible into the memory. So to interface to a DLL using a default alignment of 8 you often have to add filler bytes between parameters. To make matters even more interesting a DLL programmer can change the default alignment used for parts or the entire DLL by either using @pragma derectives in the C source code (which is usually visible in a header if you get that) or through a compiler command option, that you seldom will see if you don't get the makefiles too with the DLL (and that usually means only for DLLs where you get the source code too).
So for the API you show you could get away by replacing your arrays by clusters of 16 unsigned 8bit integers each. Other WinASPI APIs however do sometimes take structures with embedded pointers and handling that without some serious C detail knowledge is a very crash intense exercise.
09-11-2012 05:09 AM
''If you insist on going this (IMHO fruitless) path....''
Hi Rolf,
I am Adrien's internship supervisor and asked him to post his problems on the forum (I also do not have experience with DLLs and absolutely no C or C++ - LabVIEW (and a dash of Matlab) are my only languages) as I knew we would need all the help we could get;-)
First of all thank you very much for the detailed technical reply - I'm sure it will really help point us in the right direction.
I also want to add a little context to Adrien's project in case (in view of the quote above) there is an easier approach we have overlooked - as you have worked with WinASPI in the past you may be able to suggest a better approach to our problem.
We are working in a university research group which develops 'Lab-on-a-disc' platforms - microfluidic chips which has the same size and profile as a CD and where the fluids are pumped around the disks using centrifugal forces. Adrien's project is to develop a toolkit whereby we can control the speed of a conventional optical drive, position of the pickup head and (through adding a DAQ card) acquire an anaolgue signal from the pickup head. We then hope to use this as a low-cost sensing platform. Adrien's project is actually repeating work which was done before by another research group a few years ago (when did ask for a copy of their drivers but they preferred (as is their right) not to distribute thier work).
Anyway with this context I hope you may be able to point us towards an easier path (if one exists) - if not we will take your valuable advise and try to make our approach work.
Many thanks again for taking the time to help,
Kind regards,
David
09-11-2012 05:37 AM - edited 09-11-2012 05:51 AM
Well my remark about "fruitless" was specifically targeted at the attempt to interface the original ASPI API directly with the Call Library Node without using any intermediate C DLL. The reason for this is, that APIs like ASPI with functions with rather complex parameters require a level of C knowledge that makes the creation of an intermediate DLL a snap. Add to that the fact that a convoluted VI library, doing all kinds of crazy C like things in the diagram of the different VIs to prepare various parameters in a way that the C function will be able to use, is a complete nightmare to maintain in the long term. These two reasons alone make the creation of an intermediate library that can mediate between the original C API and an API that uses more LabVIEW friendely parameters a very desirable thing.
That all said, if you are specifically only targetting modern Windows systems with this, a more desirable approach would be probably to interface directly to Windows SPTI API instead of installing FrogASPI which seems just an ASPI<->SPTI translation layer anyways. And no the SPTI interface isn't easier to interface with a Call Library Node directly, but IMHO you end up doing the intermediate DLL anyways, so interfacing SPTI or ASPI shouldn't make any difference. The only reason to use FrogASPI would be if you want to maintain binary compatibility for Win95/98/ME which had no SPTI but came with a licensed version of WINASPI. But honestly who is going to support Win9x/ME for new developments nowadays? And what market could that possibly serve?
09-11-2012 05:47 AM
Hi Rolf,
Thank you for the excellent suggestion - I had somehow missed the SPTI option when doing my initial research on this topic. We'll certainly have a look at it and hopefully it will be a better option than the other approach.
Many thanks again,
David
09-11-2012 06:02 AM
Hi,
I try to do what you suggested and the LabVIEW programme is working indeed now. Thank you very much for these explanations on how LabVIEW handles these parameters. I am sure that understanding this better now, even if we do not keep going on this path, will be very useful in some futures projects.
I will start looking for the SPTI API you suggest now.
Thanks again,
Adrien