I am working on ZomB Dashboard bindings for LabVIEW, and I am wondering how would I call a C function. My library (zomb.out) is loaded at startup on the startupDll’s section of the config file, and the relevant functions are exported as C functions. I have discovered the Call Library VI, and it seems to work, except it needs the path to the dll, and if I enter ZomB.out, it complains that it is not found. How do I do this?
PS. is there a way to open the block diagram by default?
There are several ways to use the CLF (Call Library Function) node, but the typical is simply to input the name of the library in the dialog. The checkbox beneath lets you expose the param and dynamically load the library. For RT, I’m not sure there is any difference between the two options.
You’ll notice that many of the NI DLF nodes use name.* so that the code will more easily port to different OSes. This minimal spec will tell LV to use the normal library search mechanisms for the OS and use the LV search paths. It will also use the typical OS suffix.
If you still get this message, give a bit more info as to when it shows up.
One trick in LV is to ctl-double-click on a subVI to open the subVI with the diagram opened on top.
Is there anyway for it to do it the C way, and dynamically link it on deploy/run?
I have 4 calls right now, and three complain if I don’t add the library path, but one does not complain, so I can leave it blank. Is there a reason for this?
Edit: Here is the deploy error message
…
Deploying DriverStation.lvlib:Get Competition Mode.vi(29.80 K)
Deploying ZomB Init.vi(5.62 K)
Deploying Begin.vi(25.87 K)
Deploying ZomBSend.vi
Failed to download ZomBSend.vi
LabVIEW: Failed to load shared library ZomB.out:ZomBDashboardSend:C on RT target device.
Deployment completed with errors
Is there anyway for it to do it the C way, and dynamically link it on deploy/run?
Just to keep the terminology clear, the C way is really defined by the OS or the library standards they have adopted. LV is making the same calls under the hood.
Here is the help for the dialog:
Library name or path—Specifies the library name or path for the function you are calling. Enter only the library name if the library is in the search path of the system. Enter the entire path if the library is not in the search path of the system. To make the reference platform independent, use the * wildcard. If you use the C++ compiler, the names of the functions in the library are altered by a process called name mangling and are platform dependent. When you use a C++ compiler, export functions with the extern “C”{} statement in your header file in order to prevent name mangling.
Specify path on diagram—Determines if you can input the Library name or path on the block diagram. When you place a checkmark in this checkbox, path in and path out appear as input and output terminals on the connector pane for the node. When you place a checkmark in the checkbox, any library referenced in the Library name or path control will not be used. Tip You can use the path in input to unload a previously referenced library from memory. Wire an empty or invalid path to the path in input to unload any library previously referenced by the node from memory.
Are you using C++? Have you declared the entrypoints to be extern C? Does the Tip above possibly apply?
Personally, I wouldn’t use the path input. I’d use the static lib name in the dialog with a * suffix. If you use the path input, use a constant or runtime values could possibly unload the lib.
As I mentioned earlier, all of this is very OS dependent and I’m not sure about the VXWorks details. I’m not sure if dynamic loading and unloading work the same as on other platforms.
Feel free to post a picture of your diagram and one of the config dialog if that helps with the description.
I was more refering to the C linking process. You build your code, and if a function’s definition cannot be found, it remembers this, so that when it is on the cRIO, it links all the previous stubs to the actual location.
I am using extern “C” (ones that I call are in bold)
extern "C"
{
**void ZomBDashboardInit(ZomBModes mode, char* ip);
int ZomBDashboardAdd(const char* name, const char* value);**
int ZomBDashboardAddDebugVariable(const char* name, const char* value);
const char* ZomBDashboardGetString(const char* name);
int ZomBDashboardGetInt(const char* name);
float ZomBDashboardGetFloat(const char* name);
double ZomBDashboardGetDouble(const char* name);
int ZomBDashboardHasSpace();
int ZomBDashboardIsConnected();
int ZomBDashboardIsAnyConnected();
int ZomBDashboardCanSend();
**int ZomBDashboardSend();**
void ZomBDashboardResetCounter();
}
how about a zip of the ZomB stuff and Telop, Begin, and my out file?
I’ve also noticed (of my 3 c calls) the following:
void ZomBDashboardInit(ZomBModes mode, char* ip); //no library name needed
int ZomBDashboardAdd(const char* name, const char* value); //Library needed, does not give errors
int ZomBDashboardSend(); //library needed, gives errors
I added your ZomB Init.vi to the cRIO portion of the 2010 project and it was still broken wanting a library name. I entered ZomB.*, closed, and it showed that it was no longer broken. I built and it didn’t indicate any errors. Unfortunately, I don’t have a cRIO at home, so I can’t test the fix much more than that.
Since I didn’t receive your project, are these VIs being loaded using a project setup for the cRIO? If so, I believe you will be able to use the library name statically typed into the library, and the exe will link up on the cRIO the way you want. I noticed that some of the CLF nodes use the path and others don’t. Again, I don’t know all of the RT details, so I can’t say exactly why the authors did it different ways.
Make sure that your VIs are in the cRIO section of the project and that they list the cRIO context in the lower right of the window, put the ZomB.* in the dialog as the library name/path. Let me know how that works.
…
Deploying DriverStation.lvlib:CommDataCache.vi(11.25 K)
Deploying ZomB Init.vi
Failed to download ZomB Init.vi
LabVIEW: Failed to load shared library ZomB.*:ZomBDashboardInit:C on RT target device.
Deployment completed with errors
i’m using the default 2010 project.
I’ve also copied ZomB.out to
/ZomB.out
/ni-rt/ZomB.out
/ni-rt/startup/ZomB.out
/ni-rt/system/ZomB.out <- Loaded on startup dll’s
It looks a bit like the load that takes place as part of the deploy is complaining about not being able to load the library. It shouldn’t matter, but it is.
Please change the configure settings to have the checkbox for the input path, and wire up a constant with ZomB.*. Either do this for each, or comment out all but one until you don’t get a deploy error.
There is a diagram disable structure in the same palette as while loops, for loops, and case structures. Just drop that on top of what you want to disable.
Please let me know if you can reproduce these results.
I placed the ZomB Init.vi into Begin.vi and changed it to be configured to call into the ZomB.* library within the dialog. This failed to run button deploy until I ftp’d the ZomB.out into ni-rt/system, and then, as expected, Begin.vi would run fine. I built an executable that included Begin, deployed and rebooted to see it running. As far as I can tell, the call was successfully made to ZomB.out to init. It did not return an error.
If it doesn’t work please give details of how it fails.
In the call library node, you should only specify the name.*, not the path.
If you have it in the start-up DLLs, then you should see it loading in net console on boot. If that is succeeding, then the VI should not be loading it again. If it fails to load on startup, then you have a problem with your library.
Oh, silly me! I had an earlier version of ZomB in /ni-rt/system, and assumed that labview would be using the newer one in /ni-rt/startup since it deployed there!
Now that I have it working, is there anyway to generate a lvlib that can be automatically included in projects?
You’ve already gotten it to work, but for anyone else doing this level of integration, LV loads the library from the path entered – made a bit more complicated for RT targets. For that reason, most of the time, you only enter in the library name and let the OS and/or LV insert the appropriate paths. This is controlled by LibPath or a similar mechanism and includes the LV search path. Also note that some OSes may only allow one DLL with the same name to be loaded, even if from different paths or different versions.
An lvlib provides a namespace, an ability to determine what is private and public, and that is about it. If you build VIs to wrap your DLL, you can ship them in a folder and if you like, you can include an lvlib file descriptor too. You can also include a dir.mnu file.
As for where to place it, you have a number of choices. Possibly the best place to tell users to install it is into the vi.lib/addons directory. Another location is the user.lib directory. Either of these can easily integrate into the palettes and if used by the user, the VIs will be downloaded to the cRIO. I believe the users will need to install the lib on the cRIO as part of the build spec or via ftp (not sure about this one).