LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Unresponsive GUI while receiving data

Solved!
Go to solution

Hi I'm fairly new to Labview and still getting used to the dataflow programming model. I'm trying to use LV as a control panel for some software and hardware running on an FPGA for a prototype I'm creating. The communication with the FPGA is done through UART and seems to work fine. I have the problem however that my control buttons become unresponsive in some specific occasions. I think the best way to go here is that I explain what my program should do (and what I think it should be doing), post my VI, explain when it blocks and hopefully someone can help me isolate the problem.

 

As I've said LV is supposed to be the control panel, through this panel the user can change some settings and start/stop the measurement. The controls are send to the FPGA (a ZYBO board for the interested) which applies the commands and sends the measurements back. 

I based my VI on the simple state machine template and build the rest from there. I tried not to use too much variables as I've read that this breaks the dataflow model but sometimes I couldn't find any other way.

 

This is how the VI should work: after initialisation it should be in the wait for event state, waiting for a changing value from the start/stop button or the exit button. Every second a timeout event occurs and LV checks with the FPGA (and sends the commands to the FPGA). If the start button is pressed the FPGA starts measuring, in every packet it sends back the FPGA will say how much measurements there are remaining and send 60bytes of data to LV. Most of the time the UART communication is the bottleneck and the number of measurements will start growing. During this time however I'm still able to change the values of the commands I send to the FPGA (like I want). If I press the start/stop button again I send the stop command to the FPGA which means that it will stop measuring but still send data to LV. I think that the VI loops through the same states as when it is measuring (communication -> button control -> Handle Data -> communication). During this time however the GUI does not seem to respond to my button presses, it wont let me change the commands I'm sending or even use the exit button. This unresponsiveness remains while I'm receiving data. Once the number of remaining measurements hits 0 (the "nom" variable in the VI) it goes back to the "wait for event" state and at that time my previous button presses are executed. (So let's say I have pressed the stop button andthere are still some measurements to be sent, if at that moment I press the exit button it won't respond but once the communication is done it will register the exit button press and quit the VI.) 

 

I tried to avoid working with timers since the communication is the bottleneck for the moment, this is the reason why I don't go back to the "wait for event" state once the measurements have started.

 

I hope my explanation was clear, otherwise I'm happy to clarify some more (or rephrase if needed). A recap of my problem:

During the time that I am measuring and receiving data I loop through the same states as when I stopped measuring and am simply receiving data ("communication -> button control -> handle data -> communication"). When I'm measuring the GUI is still responsive and when I stopped measuring it is not. I hope someone can help me find the problem and hopefully propose a solution.

 

Thanks in advance!

 

p.s. As I've said i'm fairly new to LV programming so if you see some other "nono's"  you can also tell me in order to improve myself.

 

0 Kudos
Message 1 of 12
(3,796 Views)
Solution
Accepted by topic author Avdz

This is the nature of the beast when it comes to State Machines. This is why if you're doing time-intensive operations, you are going to need a parallel loop in order to accept user input. Look in to the Queued Message Handler architecture that ships with LabVIEW. This is essentially an event structure in a loop that sends messages to another loop via a queue. The receiving (slave) loop then acts on those messages and takes as long as it wants without interrupting the user inputs.

 

In other news, it looks like you utilized the simple state machine pretty well and grasped how to set up states and stuff. Here are a few tips none-the-less:

  • You don't need the sequence structure. Your code already follows the data flow, so you don't need to create separate sections of data. This compartmentalizes the code and in the end gets rid of LabVIEW's ability to run some of those operations in parallel to increase run speed. Sequence structured should only be used when you don't have a way of controlling the operation order (adding a Wait between two operations, etc).
  • You can move the Commands control in to the event structure and handle value changes through a shift register. There's overhead associated with reading from the control every single loop.
  • Once you look in the QMH architecture, you'll be able to get rid of all of the Exit boolean reads that you have in each case. The event structure should hold all of your controls to optimize the user input functionality.
  • You have the error cluster through each case because the template put it there for you, but you're not using it. You should ware your error clusters through so that you know if you made a mistake somewhere. Your Initialize and Comm states should have this wired for sure to see if you have a Serial setting wrong.

Cheers


--------,       Unofficial Forum Rules and Guidelines                                           ,--------

          '---   >The shortest distance between two nodes is a straight wire>   ---'


Message 2 of 12
(3,784 Views)

You definately want some loops to run in parallel.  I tend to have a loop that does nothing but instrument communications.  Depending on the instrument, I may even have 2 loops: one for sending commands to the instrument and a second for recieving the data.  I use queues to send commands to these loops (send data, stop, etc).


GCentral
There are only two ways to tell somebody thanks: Kudos and Marked Solutions
Unofficial Forum Rules and Guidelines
"Not that we are sufficient in ourselves to claim anything as coming from us, but our sufficiency is from God" - 2 Corinthians 3:5
Message 3 of 12
(3,768 Views)

Thank you for the push in the right direction. If I understand correctly the QMH is a kind of parallel state machine which is useful when you want to do two (or more) different actions at a different rate? In any case it seems that this would solve my problem. So the fact that the GUI still responds in the measuring case and not in the receiving state is simple (bad) luck and probably due to some background optimization? I admit that I haven't looked at the error handling yet and I haven't figured out yet how I should do this.

I'll try to change my VI using the QMH template and I'll update my post in case this solves it.

0 Kudos
Message 4 of 12
(3,712 Views)

Okay, so really you messed up your user interface functionality by trying to make the loop run continuously. You couldn't let it go back to the event structure state because then it would stop looping until the user did something. But that means you created this other state called Button Control that reads the controls and then keeps looping. Like I said above, you want all of your controls in the event structure, store their values if you need them in a shift register, and then do specific actions if the user presses a button.

 

Your application currently has two different states where it reads the controls and that's where you're seeing your different behaviors.

Cheers


--------,       Unofficial Forum Rules and Guidelines                                           ,--------

          '---   >The shortest distance between two nodes is a straight wire>   ---'


0 Kudos
Message 5 of 12
(3,698 Views)
Solution
Accepted by topic author Avdz

Thank you for the QMH tip. I've added my new VI for future people with the same problem. The only thing I don't really understand is the need for the refnum's and why they are needed in the initialisation, it doesn't seem to do much there (i.e. the program still runs correctly without the refnum's in the initialize state).

Message 6 of 12
(3,622 Views)

You may need to use the refnums later, that is why they are stored in the shift register cluster. For example at different states of you program you may want to disable a button, change label, etc... In this way it is easy to access the required refnum via unbundling from the cluster, in any case where you need it...

0 Kudos
Message 7 of 12
(3,608 Views)

@Avdz wrote:

Thank you for the QMH tip. I've added my new VI for future people with the same problem. The only thing I don't really understand is the need for the refnum's and why they are needed in the initialisation, it doesn't seem to do much there (i.e. the program still runs correctly without the refnum's in the initialize state).


Great job with the QMH, for a simple application like this it looks like you have just what you need. I think marking the QMH as the solution matches your post title perfectly too, because a lot of people come here with questions when their state machines lock up.

 

One thing to note is that your acquisition is completely timed by the Timeout case in your top loop. This is fine since you don't have many other events that push the timeout back often and if you don't mind if the application waits an extra second to update when the user does something. If you ever need to have a loop with even timing, you can add a third parallel loop that just does the acquisition when required.

Cheers


--------,       Unofficial Forum Rules and Guidelines                                           ,--------

          '---   >The shortest distance between two nodes is a straight wire>   ---'


0 Kudos
Message 8 of 12
(3,590 Views)

@James.M wrote:

 

One thing to note is that your acquisition is completely timed by the Timeout case in your top loop. This is fine since you don't have many other events that push the timeout back often and if you don't mind if the application waits an extra second to update when the user does something. If you ever need to have a loop with even timing, you can add a third parallel loop that just does the acquisition when required.


This is only the case when no measurements are being sent to the VI. When the user changes a setting a data packet is directly send. When the hardware has measurements to send the message loop will continue looping through the "Comm" case and continue communicating until there is no more data to be send. The only problem with this solution is that I haven't found a way to ensure a stop command is send when the exit button is pressed; or in other words ensuring that the hardware will stop measuring when the user quits the application. But for the moment it is not too big a problem. 

0 Kudos
Message 9 of 12
(3,563 Views)

Oh, I didn't realize you had it looping back to Comm over and over. This will actually eventually turn in to the queue overflowing if there is data continuously. Picture this scenario:

  1. Continuous data
  2. Timeout occurs and sends "Ping"
  3. Ping enqueues "Update SSS", which enqueues "Comm"
  4. Comm enqueues "Handle Data", which then enqueues "Comm" again
  5. Timeout occurs again and enqueues another "Ping", which in turn goes through the whole process above and you get another "Comm" in the queue.
  6. You now have two "Comm" in the queue and you end upwith weird race conditions for the Handle Data case.
  7. This repeats forever if there is always new data

What you want is actually what I said above, where the application waits for the producer (event handling) loop to tell it when to check for data. You've somewhat gone around the functionality of the timeout event.

Cheers


--------,       Unofficial Forum Rules and Guidelines                                           ,--------

          '---   >The shortest distance between two nodes is a straight wire>   ---'


0 Kudos
Message 10 of 12
(3,556 Views)