Source code © 1994-2013 Guillaume Dargaud.
Free use, distribution and modification.
Can be integrated in commercial programs, but the source/fp/lib/dll provided here must not be sold independently.
Last updated on 2013/01/19
Q: How many software engineers does it take to change a lightbulb ?
A: It can't be done; it's a hardware problem.
LabWindows/CVI is a great package from National Instruments. Its main purpose is to be a powerful tool for writing data acquisition programs, but it's really a multipurpose 32 bits C compiler, doubled by a code generator and some of the most powerful C libraries ever seen on a PC (easy to use and very complete User Interface, signal/maths and more with Advanced Analysis, Data Acquisition, VXI, GPIB 488, VISA, TCP, DDE, formatting and I/O, Utilities and finally ANSI C).
Note: I have recompiled all the .lib and .fp with CVI version 5.5 and the .fp are not backward compatible with previous versions of CVI. Sorry. You can still try to use them by linking directly to the .lib.
First things first, 2 headers that everybody should have, the iso646.h for meaningful connectors and some version of my def.h useful definitions file.
There are a few things missing from early (or even current) versions of LabWindows. Here is some code I wrote or adapted for getting the available disk size, doing on the fly statistics, doing color scaling, getting compiled Html Help files (*.chm) to display contextual help and doing extended time formatting. You can right click on a frame and select [Open frame in new window] to get a full size listing; or copy/paste the frame into your favorite editor...
Sometimes there's something wrong with a control. It doesn't behave as expected. Maybe you changed an attribute with the wrong panel/control association. And the cause is hard to pinpoint since it can happen in a totally unrelated piece of code. Unless NI makes a SetBreakOnAttributeChange function, we are stuck with looking at the properties of the control. But we can't do that from the debugger, it needs to be done from the code itself. And to further complicate it, every type of control has different attributes.
So I wrote this little module to dump all the valid attributes off a panel or control. It just prints them all. Two source files: ShowAttributes.h and >ShowAttributes.c.
Have you ever noticed that in the user interface editor you can move between panels using Ctrl-shift and the left or right arrow ? Well, here's a little piece of code that allows you to do the same thing in your C programs. In addition it will print or center your panels on request. Note that on Linux the keymaps are a bit different so you may want to verify them.
Two source files: PanelManagement.h and PanelManagement.c.
OK, so LabWindows/CVI can convert a panel or control to a bitmap and then save it as as .bmp file. Hmmm, not very useful: you can't put it on the Web and it takes a huge amount of space on the disk. The JPG format is not very adapted to saving a typical panel (the text gets hard to read because of the lossy compression), and the GIF format is limited to 256 colors and is a proprietary format. So what gives ? The only other compressed format that is common on the Web is the Portable Network Graphics (PNG) format that can be viewed in IE4 or NS4 or above.
So I got the LIBPNG library and the ZLIB library from their respective web sites and managed to compile them for LabWindows/CVI. I wrote this Function Panel to save a bitmap, a panel or a control to a PNG file, and inversely that can read a PNG file into a bitmap or a picture control. LIBPNG and ZLIB are public domain, so this FP file is too.
PNG files have a lot of characteristics we don't need here: they can have RGB 3*8 or 3*16 bits (possibly with 8 or 16 bits alpha channel), greyscale 1, 2, 4, 8 or 16 bits (possibly with Alpha channel). Palettes of 1, 2, 4, 8 or 16 colors with multiple transparencies, comment text... Basically here we save in RGB 3*8, although I have put options for Alpha channel, greyscale conversion and black&white conversion.
Saving: If your graphic card is in 16/24-bit mode, it saves 24-bits RGB colors PNG files without alpha layer; if your card is in 32-bit mode, it saves a 24-bits RGB image with the option of having the current selection in the alpha layer. It won't work with monitors in paletted mode, I didn't want to bother with palettes, although if you pay me I could implement it in less time than it takes for a French trucker to go on strike. This 3*8 RGB should be OK for most applications, but you can save room by saving as greyscale (3 times smaller uncompressed) or black&white (24 times smaller uncompressed). PNG control options such as interlacing, gamma (default is set to 1, but you might get more accurate colors with gamma set to 0.5), resolution, compression level and comment texts are implemented.
Reading: It can read any PNG file I've cared to test: paletted 1/2/4/8/16 bits, 3*8/3*16 RGB, 8/16 greyscale, alpha layers or no, but it converts everything to 3*8 bits RGB. Image comment texts are read. No gamma conversion.
I don't give the source code here because it relies on LIBPNG and ZLIB and needs a lot of source files. The FP file contains extended information on use.
Note: Do you want to generate web pages to present those nice PNG files ? Create a cgi-script exe file with LabWindows ? Then you can easily compile and use the public domain cgic106 library in version 5.5 of LabWindows/CVI (you need the possibility to do console applications). And use my PanelToCgi code generator to convert one of your existing CVI application to the web !
Some sample files: TestReadSavePng.c and a function panel (ReadSavePng.fp/lib) in ReadSavePng.zip (111Kb). Example of use:
// Saving
Png_SetParameters (1, 1, 72, Z_BEST_SPEED, FALSE);
Png_SetTextAuthor("Guillaume Dargaud");
Png_SavePanelControlToFile (PanelHandle, 0, "PanelSpeedInterlaced.png");
// Reading
Png_ReadControlFromFile(PanelHandle, PictureControl, 0, "PanelSpeedInterlaced.png");
printf(Png_GetTextAuthor());
OK, so just above here you have downloaded my fp so that you can read and save images of panels/controls/bitmaps in LabWindows/CVI. PNG files are great but for pictures you might want to use the superior compression of the JPEG format. You have to be aware of the limitations: JPEG works well with RGB or greyscale pictures but not well at all with the typical panel containing text and graphics. JPEG is also the standard image file on the Web.
So I got the JPEG-6B library from the Independent JPEG Group and managed to compile it for LabWindows/CVI. I wrote this Function Panel to save a bitmap, a panel or a control to a JPEG file, and inversely that can read a JPEG file into a bitmap or a picture control. IJG's JPEG-6b is public domain, so this FP file is too.
JPEG files are either 24 bit RGB or 8 bit greyscale. This FP accepts 32 bit arrays but will convert them. On reading, greyscales are converted to RGB. JPG does not support palettes, alpha channels or transparencies.
Limitations: It won't work with monitors in paletted mode, I didn't want to bother with palettes, although if you pay me I could implement it in less time than it takes for a French trucker to go on strike. Also I haven't implemented interlaced on saving (it will read them, though).
I don't give the source code here because it relies on JPEG-6b and needs a lot of source files. The FP file contains extended information on use.
Note: Do you want to generate web pages to present those nice JPEG files ? Create a cgi-script exe file with LabWindows ? Then you can easily compile and use the public domain cgic106 library in version 5.5 of LabWindows/CVI (you need the possibility to do console applications, so it won't work with earlier versions). And use my PanelToCgi code generator to convert one of your existing CVI application to the web !
A function panel (ReadSaveJpeg.fp/lib) in ReadSaveJpeg.zip (95Kb). Example of use:
// Saving Png_SavePanelControlToFile (PanelHandle, 0, "PanelSpeed.jpg", 75); // Reading Png_ReadControlFromFile(PanelHandle, PictureControl, 0, "PanelSpeed .jpg");
OK, so there are several predefined popups, like ConfirmPopup or GeneralPopup that you can call, and they will return the button clicked by the user. But how do I make a custom popup, for instance the classic [Yes|No|YesToAll|NoToAll|Cancel] popup ?
I mulled that one over for a while, until a suggestion from Martin J. Saxon: the trick is to call RunUserInterface again... Here's the sourcecode for the [Yes|No|YesToAll|NoToAll|Cancel] popup.
Here's another example which allows you to change the format, precision and padding of a numeric control:
Note: you may be thinking about doing the same for a graph properties popup, but this is largely done already if you use legends and enable [Interactive Legend].
And yet another example which allows you to change the format, precision and a few other attributes to a graph axis:
And yet another example which allows you to change some cosmetics on a slider popup, including the ramp colors, needle width, etc:
And yet another example which allows you to change the ON and OFF colors of a simple LED or button:
There are many default events in LabWindows, but some are missing. For instance you can drag and drop files from explorer onto a panel only if you call the EnableDragAndDrop function. Something else that is sometimes necessary is shift-click, ctrl-click and alt-click. The code is below. The thing I haven't been able to figure out yet is how to separate and get the coordinates of mouse-down and mouse-up on a canvas, which is necessary for drawing a box for instance.
#include <windows.h>
...
int CVICALLBACK cb_View (int panel, int control, int event, void *callbackData, int eventData1, int eventData2) {
BOOL KeyShift, KeyCtrl, KeyAlt;
// can be combined
KeyShift=GetAsyncKeyState(VK_SHIFT)>>8; // >>8 if the key is pressed right now,
KeyCtrl =GetAsyncKeyState(VK_CONTROL)>>8; // &0xFF if it's been pressed since the last call
KeyAlt =GetAsyncKeyState(VK_MENU)>>8;
switch (event) {
case EVENT_LEFT_CLICK:
if (KeyShift) ...;
if (KeyCtrl) ...;
if (KeyAlt) ...;
break;
...
Another trick that has to do with user input is to regroup the keyboard events to the top panel. For instance if you have a child or separate panel that catches a few keyboard event but you want all other keyboard events to go to the main one (useful for instance if the menu bar is only on the main panel), do the following in the child panel callback function:
switch (event) {
case EVENT_KEYPRESS:
switch (eventData1) { // Keyboard events recognized by child panel
case 'm': DoSomething(); return 1; // Act and swallow the event
...
}
// Key not recognized, passed to Main window
SetActivePanel(MainPanel);
FakeKeystroke (eventData1);
return 1; // We swallow the event but fake it again
}
TRecent versions of CVI have added a SetCtrlAttribute (panel, control, ATTR_XFORMAT, VAL_ABSOLUTE_TIME_FORMAT) and also a relative time format. The problem is that the data must be sent to the strip chart precisely 1s apart. Thus you cannot use a timer which lacks the precision. So I wrote this set of functions which writes the dates as text labels on the axis. It should work with an arbitrary number of strip charts at the same time.
It works quite simply: you call TSL_Auto with the expected update rate of your data, and then you call TSL_PlotStripChart to add points to the strip chart. That's about all there is to it, even if the data comes at non-deterministic intervals. It can use any resolution from one second to a year.
Here are 3 examples at various time scales:
2 source files (TimeStripLabel.c/h) and 3 test files (TimeStripLabelTest.uir/h/prj) in TimeStripLabel.zip. And here's the header file:
Strip charts are a good way to offer real-time display of data but their programming can be a tad tricky. Here's a piece of code that takes a bunch of variable pointers and gives the user the possibility to display what he wants on how many strip charts as he wants. Basically.
It works quite simply: load the GSC panel from GenericStripChartUI.uir, then call GSC_SetProperties, then call GSC_AddVariable as many times as needed. Done.
If you compile the project with the GSC_DEBUG option, you get a full example executable.Also you can compile the file with TimeStripLabel.c or PanelManagement.h for added functionality.
2 source files (GenericStripChart.c/h) and 2 UIR files (GenericStripChartUI.uir/h) in GenericStripChart.zip. And here's the header file:
XY plots are the main way to display one data versus another and here's a simple panel that will take an arbitrary list of double variables and let the user chose between them two pairs to display against each others. It will display data for a while and then remove the oldest.
It works quite simply: load the GXY panel from GenericStripChartUI.uir (it's the same file as above, but does no require the use of strip charts), then call GXY_SetProperties, then call GXY_AddVariable as many times as needed. Done.
2 source files (GenericXYplot.c/h) and 2 UIR files (GenericStripChartUI.uir/h) in the same zip file as above: GenericStripChart.zip. And here's the header file:
As of 2007, LabWindows can run as real-time. The setup is fairly complex: you develop your code on a Windows machine, in the usual CVI IDE, and then you push it onto a machine running a real-time minimalist OS called PharLap ETS. Now I've had some trouble getting that thing running. The remote machine (also called real-time target) can be a PC, a PXI box or some other compbination, but for PCs the requirements are actually pretty tight:
Now NI gives you several ways to configure the target. I'll speak first about the OS installation, then about the network config:
Anyway, to make a long story short, I wasn't able to properly run the RTOS on my test laptop: incompatible network card. It's the proper chipset but it needs to be PCI and not MiniPCI. End of the story for now.
As of version 8.0 (2007), National Instruments provides a version of LabWindows/CVI for Linux. It was updated in 2010. Here are some notes about using it.
CMPLRNAME = GCC VALID_CFG = 1 DOPARSING = 0 OPT_LEVEL = 0 WARNLEVEL = 0 USERFLAGS = COMPFLAGS = -c -x c -m32 C89_FLAGS = -std=gnu89 C99_FLAGS = -std=c99 LINKFLAGS = -rdynamic -m32 COMPLPATH = gcc ENV_BATCH = OBJ_TEMPL = -o $OBJECT SRC_TEMPL = $SOURCE DEF_TEMPL = -D$MACRO DEFVTEMPL = -D$MACRO=$VALUE INC_TEMPL = -I$PATH LIB_TEMPL = -l$LIBRARY LIBPTEMPL = -L$PATH LIB_PATHS = USE_LIBRY = nianlys;pthread;cvintwrk;ninetv ABS_LIBRY = OPT_FLAGS Debug Opt = -g Release Opt = -O2 END_FLAGS WARNFLAGS Warnings = END_FLAGS __CEND___
Some tricks:
Other resources about LabWindows/CVI include:
LabWindows/CVI Programming for Beginners;