LabWindows/CVI

cancel
Showing results for 
Search instead for 
Did you mean: 

Converting GUI-made Timers to async timers.

I am about to start the process of converting timers created in the LabWindows GUI editor over to Async Timers, created through C code. The code I am working on has dozens of Timers that will be started and stopped using API calls such as:

 

SetCtrlAttribute (panel, PANEL_MAIN_TIMER_THREAD_EVENTS, ATTR_ENABLED, FALSE);

 

I will have to manual create all the timers, and then replace all these SetCtrlAttribute() calls with the C code to start/stop the timers.

 

Before I begin this manual process, I thought I'd ask here and see if I missed some shortcut that would convert the GUI-made timers into async timers with less effort.

 

Any tips? Thanks, much! I am using the 2017 edition.

0 Kudos
Message 1 of 9
(2,003 Views)

For anyone who finds this down the line... throughout my code I find things that toggle Timers directly like:

 

SetCtrlAttribute (panel, PANEL_SVC_TIMER_EXCITER_CALIB, ATTR_ENABLED, TRUE);

 

I am replacing these with wrapper functions ("clean code" style, sorta) like:

 

StartTimerExciterCalib (void);

StopTimerExciterCalib (void);

 

Each of those calls a Set function with true or false:

 

SetTimerExciterCalib (bool enable);

 

Once I have that done, I will easily be able to update those routines to work with the GUI timer as-is, or use an ASYNC timer.  I made a test app that used a #define and #ifdef to decide how it will compile.  The original version will pause the UI (no timers) while moving it around, while the async timer keeps animating and counting when I am dragging it around.

 

That's what I hope to accomplish here.

 

 

0 Kudos
Message 2 of 9
(1,979 Views)

The only problem I see in this conceptual framework is that to operate on an individual async timer (e.g. to stop it) you must use the tier ID returned from NewAsyncTimer () function. Your start function should return this value so that you can store it in a variable and pass it to the stop routine.



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 9
(1,971 Views)

I ended up using static globals in my Timer file for the IDs. I made wrapper functions like this so I can conditionally compile either way:

 

void SetTimerRF (bool enable)
{
#if defined(USE_ASYNC_TIMERS)
   SetAsyncTimerAttribute (S_TimerRFID, ASYNC_ATTR_ENABLED, enable);
#else
   SetCtrlAttribute (GetPanelIndex (MAIN_PANEL), PANEL_MAIN_TIMER_RF, ATTR_ENABLED, enable);
#endif
}

 

But, I already ran into issues with timers not working. I was getting -2:

 

No more IDs are available to assign to a new timer.

 

I guess I can't convert all the code's existing timers over since we use too many 😉 

 

Since many of our timers run at the same rate, I should be able to do them all with one timer and just have "enabled/disable" flags for each timer I want to use...


The experiments continue...

0 Kudos
Message 4 of 9
(1,937 Views)

I already hit a snag in my conversion. I worked around not having enough Async Timers, and then started running into:

 

-129 [0xffffffffffffff7f]). This panel operation can be performed (if a top-level panel) only in the thread in which the panel was created, or (if a child panel) only in the thread in which the top-level parent panel was created.

 

Since my timer callback is now operating as a thread, it is unable to access this panel.

 

Am I going to have to rearchitect everything, or is there some workaround to get access to this panel to the Async thread?

 

0 Kudos
Message 5 of 9
(1,934 Views)

Just out of curiosity, why are you needing multiple threads for each timer?  Is that really necessary?

 

In one of my projects that is quite complex (16 software created standard timers in same thread, 6 GUI timers, 3 async timers), I've found that having a single thread for all timers and the secondary thread for the async timers is sufficiently responsive for my GUI.

 

 

0 Kudos
Message 6 of 9
(1,885 Views)

No, I do not think it is necessary at all. I think it was just a design decision made to be "easy."

 

I converted everything to use a fast timer (only one CB is fast) and a slower timer, and my own dispatch routine inside, and now things are quite zippy.

0 Kudos
Message 7 of 9
(1,881 Views)

Additional question -- if not using an ASYNC timer, there wouldn't be any need to resource lock or make thread safe variables, would there?  Everything would be running from the main context, so when a Timer CB runs, nothing is running anywhere else in the LabWindows program?

 

I did simply locking around my ASYNC timers for some globals that it uses, since my understanding is that runs in its own thread separate from the main() code.

0 Kudos
Message 8 of 9
(1,880 Views)

You are correct.  With standard timers, no need for locking.

 

And (don't tell anyone!) I've been using globals around async timers forever now.  Just be careful!

0 Kudos
Message 9 of 9
(1,867 Views)