08-08-2006 01:37 PM
08-08-2006 02:14 PM
I'm having a little difficulty in understanding your architecture. Normally, you would build a dll that contains different function calls. In other words, you would have an init function, a read function, and an uninit function. In the LabVIEW world, you do this by having three separate VIs that you include into the single dll.
A sequence structure is not something that most LabVIEW programs reqlly require in the first place and I think you might have problems with the way you are implementing it and the case statements but I would like to see the code. The default value of an exit tunnel will depend on the data type. For a string, it's an empty string. For a numeric, it's zero. And for a Boolean, it's false. You can of course define any constant you want. the only way that I see that you can have the false case pass the data that was generated in the true case is with an uninitialized shift register but all of that complexity could be avoided if you created 3 separate VIs, eliminated the sequence structure, and had no case statements.
08-08-2006 04:13 PM
Hi Dennis,
First of all, thanks for the response.
You mentioned the traditional approach is to make three separate VI's. Creating three VI's is easy enough to do, but I have data that I want each VI to see data that is generated by the other VI's. If I have three separate VI's, how do I get the data such that is static (seen) to the others? In VB I would simply create global variables and update them as needed. But in Labview's case, I am not sure how to approach this.
A flat sequence structure sounded a lot more logical to me. Here's how I envision the process:
1) Create a single Labview DLL with one VI
2) Inside the VI there are multiple function calls, each contained in either true/false case structures or an indexed stacked case statement
3) Call each Labview function by sending a index number from VB to the Labview DLL
4) Labview then "selects" the proper function call by using the selector value
5) Labview DLL then returns data in the form of a variable or array, as needed, back to VB
The beauty of this approach, I only have to create one VI and all the function calls are embedded therein. No need to open mulitple VI's and make changes to the code in each one.
Now my problem is; how do I keep data in the Labview DLL persistent after VB makes a call to the DLL. If I made a C DLL, which I have done many times, I would simply setup a variable with a DLL wide scope, such that all the function calls in the DLL can see the change to the variable. This is what I want to in Labview, but am not sure how to go about it.
Thanks, Jim.
08-08-2006 04:54 PM
A stacked sequence structure or flat sequence structure is usually used by people who are transitioning from text based languages. In LabVIEW, you use data flow. If you want to use a single case statement, that's fine. To make data persist, as I mentioned, you can use an unitialized shif register. You have a while loop around the entire VI and create a shift register for each variable that you want to maintain. Writing to a global variable shoul also work. You could have case 1 write to global variable z and case 2 read from global variable z. I've never used global variables in a dll but I can't think why it would'nt work. This should be equivalent to your variable with a DLL wide scope.
The beauty of using three different VIs is that each function call returns data wherever you have an indicator and accepts data wherever you have a control. If you call function A and it returns data x. If data x is required by function B, then data x is passed as an input to function B.
08-09-2006 10:19 AM
OK, Dennis, I am with you on using a Do...Loop for maintaining variables through the use of shift registers. I done that on several Labview projects with good success. However if I create a giant Do...Loop around the code in the Labview DLL, how does the code ever return control back to VB? Something has to cause a jump out of the Do...Loop to return out of the DLL. And when jumping out of the Do...Loop back to VB, will the variables maintained by the shift registers be held in a static state, during the change of control back to VB? Or are they by default, reset, after VB makes another call to the Labview DLL?
Maybe a more appropriate question might be:
If I create the three separate VI's needed to create the Labview DLL in the "classic" Labview programming sense, then how do I get the variables to be seen by each of the separate VI's? What mechanism is used in Labview to achieve this? In VB for example a simple DIM statement at the head of the subroutine is all that is needed to make the variable visible to subroutines in that particular module (VI). Likewise, if I have multiple modules (VI's) and need a system wide variable, then I create an additional separate module that contains only Global variables, thus enabling a program wide scope for their manipulation. Does Labview, when adding three separate VI's to create a DLL, require the same approach? I sounds like I need to use Labview globals somewhere in my project. True? And if so, where do I put them?
08-09-2006 10:52 AM
First of all, it's called a while loop or for loop in LabVIEW. With a while loop, if you wire a false constant to the termination terminal, it will execute once. If you wire a 1 to the count terminal of a for loop, it will execute once. With an unitialized shift register, it will retain it's value as long as the VI is kept in memory. This is the basis of what is called a LabVIEW-2 style global. There have been numerous posts on this subject and is also discussed in the shipping documentation for LabVIEW. As long as your VB code does not remove the dll from memory, this should work that same way.
I guess I don't understand where the confusion is with the three separate VIs and getting variables seen the others. For a simple example, say you have a VI that calculates the sum of 2 numbers so you have two controls and an indicator in this VI. This sum is needed by a second VI so you have a control called 'sum' in this second VI. If made into a dll with two separate function calls, when you call function one, you pass it the two numbers you need to add and it returns the sum. You store the return value in your VB code and when it's time to call the second function, you pass it the value that you've saved. This would be no different than if your VB code calculated some value that you wanted to pass to any other type of dll - not just one created in LabVIEW. I could post a LabVIEW example that calls a dll but I don't know if that would help you any. I don't have VB installed at this time and really don't want to have to do it. Here's a picture of how I would break up the single VI into separate ones.
08-09-2006 11:57 AM
OK Dennis!! Your last reply really cleared things up for me. You are saying that each VI in Labview is treated as a completely separate entity where all the variables are local in scope, only to that VI. And, the only way to allow multiple VI's to see each others data is by passing parameters during calls to each VI. I can understand and work with that.
It does seem to be a limitation however when creating a Labview DLL for a rather large project that utilizes 10's or 100's of variables that need to be shared with all the VI's in the DLL. I have several projects that do indeed contain this many variables. VB (or C) for example gives much more flexibility in the way these variables can be shared amongst various function modules. I kept probing in my questioning in hopes that Labview would also offer this flexibility. It seems the only way to accomplish the task of passing large quantities of variable data is create structures of these variables and pass them back and forth to the various VI's needed for the project. Of course this means more overhead for the program while running because of this movement in memory.
OK, at least I know now what is expected for utilizing Labview DLL's, and thanks for your kind comments.
08-09-2006 12:14 PM
No problem. I'm glad things are a little clearer.
The way I've described is not the only way you could do this of course. I just thought it was the simplest from the brief description you gave. To avoid the complex structures, you could also use global variables. In the example I posted, the first frame of the sequence structure could write to global variable 'A'. The second frame could have a read of global variable 'A'. As long as the dll is kept in memory, the contents of global variable 'A' will persist so the sharing you use in VB and C is also possible. The downside of this method as I see it is that you have to be very careful about the order in which you call the single function and it' more difficult to validate the data stored in the global. If you went this way, you would probably want to add some additional error checking in the LabVIEW program to make that what is written to the global is okay.
08-10-2006 10:38 AM
08-10-2006 11:22 AM
Well, it makes for ugly LabVIEW code though.
Local and global variables break the dataflow design of LabVIEW and your design would get poor marks if it was to be used strictly in LabVIEW. Also, every time you use a local, you create a copy. With large arrays, this can pose a problem. When I mentioned globabl variables, I should have mentioned that is preferable to use what is called a LabVIEW-2 style global variable. What this is basically a VI with an unitialized shift register. There's additonal information on these in the shipping documentation but they avoid the data duplication problem and race conditions.
Obviously, I can't see your false case in the first frame but I don't understand the point of writing some constants to the local variables 'Array 3' and 'Last Data Number 2'. If these are constants necessary for frame 2, why don't you just place the constants in frame 2? Since you are initializing the shift register in frame 2 with them, every time frame 2 is called, it will start with the defaults. You are not writing to the local variable when frame 2 finishes.