LabWindows/CVI

cancel
Showing results for 
Search instead for 
Did you mean: 

Using multiple instruments with the same controls

Hi, I am using Labwindows 7.1. I have 20 of the same instruments (power supplies) that I will be communicating with via GPIB. For each of these instruments I will be having many of the same controls with and without callbacks. Is there an easy way of using these controls instead of having to repeat so much code. I know Labwindows doesn�t support an array of controls.
Is there a way of appending the �i� to the end of the control name (see bellow) for PANEL_VOLTAGE_ and the others because you can not declare these control names as part of an array, such as I have bellow.

case EVENT_TIMER_TICK:

for (i= 0; i < NUMBER_OF_SUPPLIES; i++)
{
SGA_MeasureDCVolt (instr_handle[i], &VOLTAGE_VAL[i]);

SGA_MeasureDCCurr (instr_handle[i], &CURRENT_VAL[i]);
SGA_OutputOVPQuery (instr_handle[i], &OVP_VAL[i]);

SetCtrlVal (panelHandle, PANEL_VOLTAGE[i], VOLTAGE_VAL[i]);
SetCtrlVal (panelHandle, PANEL_CURRENT[i], CURRENT_VAL[i]);
SetCtrlVal (panelHandle, PANEL_OVP[i], OVP_VAL[i]);
}


And what about the callbacks? Is there a way of not having to have 20 callbacks all doing the same thing (like OOP)? Repetition of so much code will be hard to debug and not good for maintenance!

Thanks
0 Kudos
Message 1 of 7
(3,856 Views)
You are correct that you cannot create an array of controls in the UI editor, but there is nothing from stopping you creating an array of controls programatically (using NewCtrl, etc). The disadvantage to this is that you have to do the control layout by hand in code rather than in the UI editor (although you can do the layout in the UI editor the use the UIR to code converter; however, this will not create the arrays you're lookging for; you'd have to go back in and modify it by hand).

Also, there is no problem with having all of the same controls share the same callback; you can easily distinguish between them by using a different callback data value.

Hope this helps,

-alex
0 Kudos
Message 2 of 7
(3,856 Views)
If you can group all control related to one instrument in a little panel, you could load it as a child on your main panel, next replicate the child panel assigning a different handle to it; those hadles can be grouped in an array of int.

This way, when a callback is triggered you can discriminate which instrument is operated on by means of the panel handle passed to the callback.



Your timer callback will look as follows:

case EVENT_TIMER_TICK:


for (i= 0; i < NUMBER_OF_SUPPLIES; i++)
{
SGA_MeasureDCVolt (instr_handle[i], &VOLTAGE_VAL[i]);
SGA_MeasureDCCurr (instr_handle[i], &CURRENT_VAL[i]);
SGA_OutputOVPQuery (instr_handle[i], &OVP_VAL[i]);


SetCtrlVal (panelHandle[i], PANEL_VOLTAGE, VOLTAGE_VAL[i]);
SetCtrlVal (panelHandle[i], PANEL_CURRENT, CURRENT_VAL[i]);
SetCtrlVal (panelHandle[i], PANEL_OVP, OVP_VAL[i]);
}




At the beginning of the application you will need to create the array and populate it with the panel handles:

int panelHandle[NUMBER_OF_SUPPLIES];

mainH = LoadPanel (0, "uirfile.uir", MAINPANEL);

panelHandle[0] = LoadPanel (mainH, "uirfile.uir", PANEL);
// Set appropriate panel position
DisplayPanel (panelHandle[0]);
for (i = 1; i < NUMBER_OF_SUPPLIES; i++) {
panelHandle[i] = DuplicatePanel (mainH, panelHandle[0], "title", top, left);
DisplayPanel (panelHandle[i]);
}
DisplayPanel (mainH);



Inside the control callbacks, discriminate the interested instrument:

int CVICALLBACK InstrCbk (int panel, int control, int event, void *callbackData, int eventData1, int eventData2)
{
int actInstr; // Instrument operated on

for (actInstr = 0; actInstr < NUMBER_OF_SUPPLIES; actInstr++) {
if (panel == panelHandle[actInstr]) break;
}

// Your code here
}



One disadvantage of this approach is that tabbing through controls does not fall into and outside child panels: your operator will need to use the mouse to change the instrument to act on.


Hope this workaround can be useful for your needs
Roberto


Proud to use LW/CVI from 3.1 on.

My contributions to the Developer Community
________________________________________
If I have helped you, why not giving me a kudos?
0 Kudos
Message 3 of 7
(3,856 Views)
Unfortunately, for this idea, I have the restriction of having all the controls to be on one panel. The user needs to be able to control all power supplies on the same screen.

Thanks for the effort.
0 Kudos
Message 4 of 7
(3,856 Views)
That's not a problem: I spoke about child panels exactly with the intention of having all controls contemporary visible. Loading individual instrument panels as child of a large main panel (perhaps displayed full screen) permits you to display all panels at the same moment. You can also configure child panels to have no border or a simple outline and no titlebar, so that they look similar to a decoration used to group controls together.

Your operator will be able to see and control all instruments from one (main) panel only, with the only restriction that he will be not able to pass from one control to another with the TAB key (unless you write some code to help this movement, which is not so difficult).

I am attaching a simple
example of my solution: take a look and see if it can fulfil your needs.

Roberto


Proud to use LW/CVI from 3.1 on.

My contributions to the Developer Community
________________________________________
If I have helped you, why not giving me a kudos?
0 Kudos
Message 5 of 7
(3,856 Views)
Hi.

I suggest the following:

1. Open your panel in the UI editor.
2. Erase the controls for all but the first instrument.
3. Arrange all of the controls for the first instrument on your panel. Give them names like VOLTAGE_VAL_1, CURRENT_VAL_1 etc, and arrange them as you like. Note: the "_1" is important. Assign callbacks where you need them.
4. Select all of these controls, then copy & paste (Ctrl-C, Ctrl-V). Use the arrow keys to position the copies.
5. Repeat Step 4 until you have a set of controls for each instrument.
4. Press Ctrl-T to edit the tabbing order.
5. Click each of the controls for Instrument 1 in the order you want.
6. Repeat Step 5 for the remaining Instruments, making sure that you click them in the same order for each.

7. Mod
ify your code to something like this:

case EVENT_TIMER_TICK:

for (i= 0; i < NUMBER_OF_SUPPLIES; i++)
{
Offset = i * NUM_CONTROLS_PER_INSTRUMENT;

SGA_MeasureDCVolt (instr_handle[i], &VOLTAGE_VAL[i]);
SGA_MeasureDCCurr (instr_handle[i], &CURRENT_VAL[i]);
SGA_OutputOVPQuery (instr_handle[i], &OVP_VAL[i]);

SetCtrlAttribute (panelHandle, PANEL_VOLTAGE_1 + Offset, ATTR_CTRL_VAL, VOLTAGE_VAL[i]);
SetCtrlAttribute (panelHandle, PANEL_CURRENT_1 + Offset, ATTR_CTRL_VAL, CURRENT_VAL[i]);
SetCtrlAttribute (panelHandle, PANEL_OVP_1 + Offset, ATTR_CTRL_VAL, OVP_VAL[i]);
}

8. In your other callbacks, you can determine which instrument you are working with by comparing the "control" parameter with PANEL_START_BUTTON_1, etc.

Hope this helps,
Colin.
0 Kudos
Message 6 of 7
(3,856 Views)
In my opinion this approach, which indeed can work, has two main disadvantages.

1. It is rigid: a change in the number of controlled instruments implies a heavy modification in the UIR file and in the source.

2. It is dangerous: little modifications on the UIR file can alter numberation and order of controls, so that the "offset" value is no longer valid if new controls are added that fall inside the progressive numberation of controls.

With respect to item #2, I suggest to create an array of control handles into which to store the control IDs of numerics and buttons.
For example:

int ctrl[NUMBER_OF_SUPPLIES * 10];

ctl[0] = PANEL_VOLTAGE_1;
ctl[1] = PANEL_CURRENT_1;
ctl[2] = PANEL_OVP_1;

ctl[10] = PANEL_VOLTAGE_2;
ctl[11] = PA
NEL_CURRENT_2;
ctl[12] = PANEL_OVP_2;

// ...

ctl[100] = PANEL_VOLTAGE_11;
ctl[101] = PANEL_CURRENT_11;
ctl[102] = PANEL_OVP_11;

// And so on

The routine will then be as follows:

for (i = 0; i < NUMBER_OF_SUPPLIES; i++)
{
Offset = 10;

SGA_MeasureDCVolt (instr_handle[i], &VOLTAGE_VAL[i]);
SGA_MeasureDCCurr (instr_handle[i], &CURRENT_VAL[i]);
SGA_OutputOVPQuery (instr_handle[i], &OVP_VAL[i]);


SetCtrlAttribute (panelHandle, ctl[0] + Offset * i, ATTR_CTRL_VAL, VOLTAGE_VAL[i]);
SetCtrlAttribute (panelHandle, ctl[1] + Offset * i, ATTR_CTRL_VAL, CURRENT_VAL[i]);
SetCtrlAttribute (panelHandle, ctl[2] + Offset * i, ATTR_CTRL_VAL, OVP_VAL[i]);
}


Just my two cents.
Roberto


Proud to use LW/CVI from 3.1 on.

My contributions to the Developer Community
________________________________________
If I have helped you, why not giving me a kudos?
0 Kudos
Message 7 of 7
(3,856 Views)