06-02-2006 04:50 PM
06-03-2006 04:01 AM
From what you are saying, I got the impression that you are developing a single-threaded application, which in some case is not the best solution to face the actual problem.
First of all, the code snippet you posted is not complete (if (frame ready) routine start is missing the same as while loop start and we have no detail about data acquisition) but it seems that you have not any ProcessSystemEvents in the while loop, and that is why your program does not react to user pressing buttons and so on (user interface events are not processed). Anyway, I must warn you that calling ProcessSystemEvents while in a loop may drive you to unpredictable conditions if the user acts on controls which is not supposed to operate on in this moment. You must pay particular attention to which control is operable and which not during your function and place adecuate measures to limit operator activity (for example disabling unwanted buttons). However, I suggest you to consider splitting the application in two threads if it's not already: spawn a second loop to process communication with the headtracker and manage user operation in the main loop, using a set of flags to handle the offset and end-of-acquisition condition.
Second hint, you are acquiring MPANEL_DATAFLOW value only if you are saving data to disk: since this value is the while loop ending condition, you may want to read the control value out of the if (fileFlag) block.
Third hint: while testing the end-of-loop condition, you are actually SETTING the value of user_seln, instead of testing its value: you must change the statement to while(user_seln == 1);
I hope this can help you to improve your application performance.
Roberto
06-04-2006 10:56 AM
Hi,
Thanks for the prompt reply. I have never used processsystemevents before . Where should i incorporatte it into my code. I mean where in the callback function GETHEADTRACKERDATA. .I have attached a copy of my whole code
I have made the other corrections.
Waiting for a reply
Kunal Chaniary
06-04-2006 01:10 PM
06-06-2006 09:59 AM
Roberto should have you on the right track as far as getting your user interface to respond. I am going to add a little more about your program design, in the hope that you get a better understanding of the issue. Your problem starts in GETHEADTRACKERDATA(). I am not sure what calls this, but I assume it is some form of button control. The problem is that this function does not ever return control back to the event handler that CVI uses. As you have probably read, CVI is an event driven programming model, that is each action it takes is normally the response to some event such as the EVENT_COMMIT generated by a keypress. Once of the basic ideas of event driven models is that each action does what it needs too and then returns control back to the program to process other events. Normally this return of control happens very quickly. In GETHEADTRACKERDATA() you have a
do { /* until keypress*/
}while(user_seln=1);
The problem of course is that this "do loop" does not exit any time soon. As a result your program continues to acquire bird_data, which you probably want it to do, but at the same time ignores everything else, which you do not want. If you have other functions tied to events, like a keypress or a button press, they are never seen by the event handler. In event driven programming this is known as blocking, and as you have seen the result is poor or no response in the user interface.
If the solutions provided by Roberto do not get you to where you want to be, or if you just want to explore other program designs take a look at adding a timer callback. By adding a standard CVI timer you will not be creating anything too complicated. Everything will still be in one thread. With everything in one thread, only a single set of actions will occur at one time, so you do not have to worry too much about your program hopping from one section of code to another. The timer simply generates an event at some interval you specify. This is kind of like having an operator push a button for you at regular intervals. The event you get is EVENT_TIMER_TICK, it is very similar to the EVENT_COMMIT you get from a button being pressed.
As long as your head tracker is not returning data too fast [very hardware dependant, but lets just say each 250mS] what you would do is modify your program so that the part of GETHEADTRACKERDATA() that is inside the do loop is moved to the timer callback. Set the timer up for 200mS ( just a little faster than the 250mS of the head tracker). The GETHEADTRACKERDATA() routine you currently have would just initialize the head tracker and then start the timer. The timer will generate an event each 250mS. Your timer callback function would check for head tracker data to be available, if it is not, it will return right away. If data is present, get it and display it just as you do now, but only get one packet, then return.
Oddly enough you do not want to place any ProcessSystemEvent() calls inside the timer callback. While the timer callback is executing you will let it block the other parts of the program. The key here is that it must finish in less than 200mS (or whatever you timer update value is) for the program to run correctly. Now your data acquisition from the head tracker is driven by a timer event and your program will fit neatly in the event driven model of CVI.
You will also find that it is easy to make your Get Data button for acquiring the bird data just a simple on/off switch that enables or disables the timer.
If you have any questions please ask. Myself, Roberto and others here are more than happy to help.
Good Luck.
06-07-2006 07:34 PM
HI,
Thanks for the replies. I did use ur idea roberto of placing Processsytemenents() before MPANEL_DATAFLOW. I still have the same problem of losing control with my uir. The data would stream in but as before no control on uir. I have attached a copy of the modified code (program1)
Also i did try the new idea of using EVEN_TIMER_TICK to control the flow of data. I have modified some part of my code but still have some problems
check my code in attached file (program2)
U mentioned in your message of using GETHEADTRACKERDATA() to only initialise the headtracker and start the timer. I have initialised the headtracker using birdStartFrameStream . This command starts streaming bird(headtracker) data frame. How do i initialise the timer here( i m not getting the idea).
Also i have removed the
do { /* until keypress*/
}while(user_seln=1);
statements coz i guess this would not serve the purpose of the timer. Am i right. All the other code between do and while has been included.
Also u mentioned making a Get Data button for acquiring the bird data just a simple on/off switch that enables or disables the timer. I have used a simple on/off switch with name timerflag. When on, the timerflag is equal to one and would acquire the data.
I am not quiet sure where to place the last two lines (i mean would it go in the getheadtrackerdata fn or timercallback)
birdStopFrameStream(GROUP_ID); /*Stops streaming of bird data frames*/
birdShutDown(GROUP_ID);
Also the headtracker is streming data at 120Hz or 8.3 ms. I have assigned timer in uir a value of 8ms. I have two command buttons on uir for SETOFFSETCORRECTION and STOPOFFSETCORRECTION. Will i be able to use between the data flow after using the Timer_event_tick.
thanks again
06-08-2006 12:11 AM
Kunal,
your first version of the program should work, provided that you modify the while loop condition adding a double-equal sign! As I already told you, with your while(user_seln=1); you are actually setting the value of user_seln to 1, and this happens before the while condition is evaluated that is the while loop never ends!
As per the second program, I suppose the timer is always enabled: so you must setup a callback for the switch button that tests its value on EVENT_COMMIT; something like this:
GetCtrlVal (panel, control, &sts);
if (sts) {
// Inizialize your headtracker
// Instructions you put in GETHEADTRACKERDATA
}
else {
// Stop the headtracker
birdStopFrameStream(GROUP_ID); /*Stops streaming of bird data frames*/
birdShutDown(GROUP_ID);
// Flush the serial port discarding all residual bytes in the queue
}
Hope this helps
Roberto
06-08-2006 02:14 AM
06-08-2006 11:36 AM
We have two different approaches to getting through the user interface issue here so I have to be careful I don’t create more confusion than I clear up. Unfortunately discussing an application like this in a forum can be a bit like pealing an onion. As we get more detail of what you are trying to do, we find that some of the simpler solutions may not really be able to handle all the requirements.
You have some good questions here so here it goes:
>>U mentioned in your message of using GETHEADTRACKERDATA()…
As far as initializing the timer, what I was thinking at the time would be for the callback that starts data acquisition to make the callback for your timer active through a call to
SetCtrlAttribute(panel, control, ATTR_ENABLED, 1); where the control is your timer control.
Then set the head tracker to start streaming data.
When you want to stop retrieving data you reverse the process, stop the head tracker, then call SetCtrlAttribute(panel, control, ATTR_ENABLED, 0);
But it is also ok to leave the timer running and check the state of the switch control as Roberto suggests in his reply. And your method of using a timer flag would also work fine. There are a lot of different ways to implement things; there are advantages and disadvantages to some methods, but it is really what you feel most comfortable with that counts.
>>Also i have removed the…
That is correct, you do not want a loop, the timer callback takes place of the loop. You basically have it set so your timer tries to execute the callback every 8mS in your program2. You can think of it as a loop that tries to execute every 8mS.
>>I am not quiet sure where to place the last two lines…
I created some confusion when I said you could just create a control to use as an on/off switch. When you create an on/off switch for something you can do something like this:
If (event==EVENT_COMMIT)
{ GetCtrlVal(panel, control &switchState)
If (switchState==1)
{ // configure the device to be on here
}
Else
{ // configure the device to be off here
} // end of if(switchState)
}// end of if event is EVENT_COMMIT
You have a function in your program for GETHEADTRACKDATA() that starts the data acquisition, but you do not have one that stops it. You can create a separate stop function like you did for the offset feature or you can use a single binary switch control like I describe above. Again, what ever way makes you more comfortable. Either way you want to place the function calls
birdStopFrameStream()
birdShutDown();
SetCtrlAttribute(panel, timerControl, ATTR_ENABLED, 0); or in your case timerflag=0; in the function that stops acquisition.
Once last thing; 8mS is really fast for a windows based timer loop. Depending on how efficient things are, you may be able to do it, but you are very near the edge of what works well under a single thread in windows or on some older systems what can be made to work at all. I assume the baud rate of the serial port is pretty high, and that birdGetMostRecentFrame() executes in far less than 8mS. If it does not, the timer event will get blocked and the callback will start to fall behind the data stream from the tracker.
06-08-2006 11:41 AM