04-20-2009 06:58 PM
Hello!
I have a tab control, with several buttons on different pages.
In the current situation, we can talk about two pages, where one page "Settings" has a START and EXIT button, while second page "Wait" has an EXIT button.
In a while loop inside a flat sequence, I have an event structure, which handles events of the START and EXIT (EXIT1) buttons of the Settings page. This is fine. But I also want to control the Exit button of the Wait page, when the datasocket on a remote computer (location to be changed instead of "localhost") is being connected. The connection to a remote computer's datasocket server takes around 10 seconds (timeout) and during this time, the "Wait" page is being displayed. I want the program to stop immediately when the EXIT button (EXIT2) is clicked on the Wait page.
The control works like this:
When I click on Start in the Settings page, the front panel shows Wait page and attempts to connect to a datasocket server on the remote computer. If the user wants to stop this process, he can click on Exit on Wait page too. But, this doesn't give any immediate effect. On the event of Start button, the front panel is not locked, so the user can actually click the Exit button on the next page when it's visible. But it's of no immediate effect. Means, what the LabVIEW does is, finishes the execution of event in Start button's click, and while this executes, it doesn't consider the Exit button's refreshed value (shown in Red circle in the block diagram's image). It considers EXIT2's value False evenif it's clicked, and this means the effect is only after the end of the event actions.
Simple question: Is there any way to check/use the updated (latest/live) value of a control during some event's execution? In another solution I have created a "value change" event of the control whose value I want to consider, but here, I want to consider the "change" that occured after an event is started.
Thanks ahead.
04-20-2009 07:49 PM
Hi Vaibhav,
Well... hummm... Where to start...
Well, I could not open your VI because this PC does not have LV8.6 installed. However, looking at the image of your partial block diagram, there are a few issues that you may need to overcome. Instead of listem them all, I would recommend that you change the design pattern to something like the "Producer/Consumer Design Pattern (Events)". Basically, that would involve having a While Loop at the top which contains the Event Structure. It would communicate events to a state machine (bottom loop) by using Notifier or a Queue.
Here are some observations from the image you posted:
Since I cannot see the entire code, I cannot tell if you have a race consition with the property nodes and the local variable at the left of the Event Structure. You have many tunnels which are not fully wired from other cases, etc and set to default if unwired. While it might be okay in certain situations for booleans, it is not recommended for references to your data sockets.
I don't understand why you have a flat (or worse a stacked) sequence structure around the While Loop. It's usually not a good sign. Maybe there is some initialization frame in front... I can't see it.
I recommend you start by seperating the user events loop from the main operations loop. There are plenty of code examples on the forum and you can also do a search under the Help Menu and selecting Find Examples.
RayR
04-20-2009 08:27 PM - edited 04-20-2009 08:30 PM
Another problem is that you have a second event structure with some of the same events. That structure won't run until your main central while loop ends. But it will still be accumulating all the events that occur during the operation of the program. And that event structure may never run because it is inside a case structure. So you may have some really unexpected behavior depending on how the user uses the program and what events fire in what order.
Another problem is that you establish a data socket connection, but if one of any number of events or cases run, the data socket reference will become a default value. So when the Data Socket close runs in the final part of your code, your reference will likely be invalid and will raise an error. You use for quite a few tunnels "Use Default if Unwired" setting. Some of those tunnels seem to be duplicates of each other, or the booleans have logic that seems to flip back and forth in confusing manners. "Use Default if Unwired" is dangerous to use because it will always use the default value of a wire (False for booleans, 0 for values, empty values for more complicated types), even when that isn't what you wanted but just forgot to code up some real logic to it.
For Ray's benefit, here is that VI saved for LV 8.0.
04-20-2009 08:52 PM
Thanks Ravens Fan,
I didn't look at the code yet, but it sounds like a re-design is definitely needed..
As I suggested earlier, the simpler way is 2 loops. Top one with an Even Structure. Bottom one with a state machine.
As for the use of Queue / Notifier, it's up to you.
I may have a look at the code in the morning.. 😉
R
04-21-2009 01:25 AM
OK, I had a quick glance at the VI (thanks for attaching the code).
First, a lot of your code makes very little sense and has many glaring mistakes, for example:
I strongly suggets to rewrite this all from scratch. Use a simple state machine with a single event structure in a single loop to handle the User intereactions and use consumer loop to handle the datasocket connections(e.g. linked by queue).
Maybe a single exit button is all you need. Don't duplicate everything to all tabs. You can either place the button next to the tab structure of float it over it. Use a simple "value change", a "key up" on a boolean button seems anti-intuitive.
04-21-2009 09:16 AM - edited 04-21-2009 09:21 AM
Thank you all for your attention and many tips.
Would try to respond on each point individually.
@ RayR
Basically, that would involve having a While Loop at the top which contains the Event Structure. It would communicate events to a state machine (bottom loop) by using Notifier or a Queue.
What do you mean? Right now also, the Event Structure is inside the While Loop. No?
Yes, I also agree about "set to default if unwired" not being a good idea, but what to do when I have datasockets in the next frame/outside the structure? To create datasocket nodes in each frame?
That flat sequence structure is just to do some initialization of the controls, as you guessed so. Any other better way to do it?
As I suggested earlier, the simpler way is 2 loops. Top one with an Even Structure. Bottom one with a state machine.
What do you mean by State Machine? I am looking at some forums to know about this.
@ Ravens Fan
That second event structure, inside "While Loop 2" is for the whole lot of controls which will be executed after the first phase, inside the flat sequence and "While Loop 1" is over. Of course, I don't want it to run until the main (first) while loop ends. The original query was about the event structure inside the While Loop 1. While the START button's "value change" event is executed, and if the user clicks on another button (Exit2), the program will not consider the changed value of the EXIT2 button, until it finishes executing the current event's code. How to overcome that? Because, for datasocket to establish connection with a remote server, it takes around 10 seconds (10000 ms) and in the event of the START button, I have "not" locked the front panel, so basically the user can click on the EXIT (EXIT2) button on the page that he'll see ("Wait" page).
Another problem is that you establish a data socket connection, but if one of any number of events or cases run, the data socket reference will become a default value.
I didn't understand this. Why would it become a default value? Because I have used the "use default if unwired" ? But what about the cases/events when I have explicitely created a datasocket node?
But I am also more concerned about the problem that you've mentioned. I use too many "Use Default if Unwired" setting. Earlier I didn't do it, but started using it as I thought it's a way to handle cases when I cannot create node (of datasocket for example) in each event case. Again, as I posted to Ray, would ask you, how to avoid that?
@ altenbach
- yes, as I mentioned above, I don't mean the second while loop on the right to start before the first loop is finished. And the events that I expect in the second loop's event structure are going to be after the first loop's events, so I don't need to service them. Because the events that I expect in the second loop will be from controls which will be
available to the user only after the execution of the first event structre/while loop 1.
- Only during the "Value Change" of the START button in the first event structure, I need to handle the concurrent change in the Exit button (I expect EXIT2's value change, as the user will see that control and will be able to click).
- You create all these datasocket connections, but you drop the connections before having a chance to ever close them because the connection ID will reset to defaults in most cases at the output tunnels. This means the "close ds" will fail anyway.
I don't understand this. Why would this happen? The datasocket connections will be created only in case the "START" button is clicked and then if the program is supposed to be ended (by clicking any EXIT button), the created datasocket connections will be terminated (Closed) in the second case structrue on the right side.
- I do a lot with local variables and property nodes because to use the same control's value on several occassions. And these disconnected terminals are because I want to show, for example, the Connection Indicator on each page, but don't know how can I have just a single indicator with multiple copies which change values altogether. So I have created
separate controls and manage them separately. This was my another question that I thought would need to ask in separate thread or search the forum.
@ All
For the sake of simplicity I posted a part of the code which highlighted the problem area. But seems like, I need a complete rebuilding of the program's structure. And I agree with all of you that the design is not a very good one. But then, my purpose is something as I am mentioning in the block diagram and flowchart attached with this post. In case, any if you don't have visio, I am attaching a jpg version too.
Am also attaching the complete program (this time converted into LabVIEW 8.0), along with two SubVIs. Also, this is just the Client program. There is also a Server program, with which this program is supposed to communicate on the created Datasocket server addresses.
Right now attaching just the client program, but if needed, I can attach the server program also.
For your suggestions, you may make changes on the visio files or my VI. If you have any better suggestion to remove the confusion / mess of my diagrams, please, I would be more than thankful.
Just to summarize the objective of this program:
At first, in the first While loop upon clicking the START button in the "Settings" page, the client tries to establish connection with the Datasocket server on remote computer, and during this period the "Wait" page is displayed (any way how to change the text of the front panel labels, programmatically?), then if this is done, the program moves to the right side Case structure with a Timer loop to receive messages from datasocket server and read them periodically, on a processor which is free (this is a new feature in LV8.6 so I used timed structure to use available resources) and another While loop which has all the events for the next controls. Now, the user should see controls where he can select to Login or Connect to the remote server - pages like "Start" or "Login" or "Register" - and the client program will communicate to the Server program. During this process, again the "Wait" page is displayed (it should be a different message this time, to be more precise, but for now, I don't know how), and then the server is approached and it responds that the login/connection request is fulfilled. If the server doesn't respond this within, say, 15 seconds, then it would be assumed that the server (application, not datasocket server) is not running. But don't have any way to do it. So I thought to provide an EXIT button on the "Wait" page so that the user can terminate the program. Because during this "connecting..." time, the front panel is not locked. Ok, after this, the program may show the final page of "Operations" and the user may disconnect and connect again.
So basically, the events for all the major controls would be in the While Loop2. But the initial controls would be in the While Loop1. Is there a way that I can just use one while loop and include all the control events in that, so that a user can move to the very beginning of the program and start again, without terminating the application? But also transferring my data?
Attachments: 1) Client_flow.zip has diagrams I made this morning, for a rough idea. they are in PNG and Visio formats.
2) Terminate.zip has VI's in 8.6 and 8.0 formats.
I am not very much fluent with LabVIEW to play as I want, because either something is a limitation of my knowledge or something is LabVIEW's limitation. And now am approaching a deadline to finish this application, which is a demonstration of our research ideas. Your tips would surely make the difference.
Thank you all.
04-21-2009 11:12 AM - edited 04-21-2009 11:13 AM
Vaibhav wrote:Basically, that would involve having a While Loop at the top which contains the Event Structure. It would communicate events to a state machine (bottom loop) by using Notifier or a Queue.
What do you mean? Right now also, the Event Structure is inside the While Loop. No?
Yes, I also agree about "set to default if unwired" not being a good idea, but what to do when I have datasockets in the next frame/outside the structure? To create datasocket nodes in each frame?
That flat sequence structure is just to do some initialization of the controls, as you guessed so. Any other better way to do it?
As I suggested earlier, the simpler way is 2 loops. Top one with an Even Structure. Bottom one with a state machine.
What do you mean by State Machine? I am looking at some forums to know about this.
Unfortunately, I could not open your code. Even what RavensFan posted (I got the following error message).
Euh.. yes, you do have an Event Structure within a While Loop which is good. What I am suggesting is in-line with Altenback's comments which, in this case, would mean having the While Loop with the Event Structure by itself; meaning not within some other structure. The idea of having a state machine is that you can use the shift registers to pass the data from one state to another, thus eliminating the problem of the default tunnel values. A state machine can be described as a Case Structure within a While Loop. Each case represents a state which are typically indexed by a TypeDef Enum control which contains a list of the states.
I will prepare a very simple example of the design approach that I mean.
RayR
04-21-2009 11:53 AM
Attached is a brief example.
Sorry, I have no time to explain the code because I have to run to a meeting.
Hope it helps to understand what I was explaining.
R
04-21-2009 12:29 PM
Ray.R wrote:
Unfortunately, I could not open your code. Even what RavensFan posted (I got the following error message).
![]()
I'm sorry about that Ray. I never tried opening the file after I did the save for previous version. (It was from my home PC)
Something must be seriously screwed up in that VI. I did a Save For on my work PC for versions 8.0, 8.2, and 8.5. Every time I try to reopen it in LV 8.6, it gives me an error message and says LabVIEW must close. If is do a Save As and leave it in 8.6, it opens okay. But even that newly saved file won't save backwards.
Vaibhav, you are getting good assistance from Ray and Altenbach. With something like the data socket node, once it is created, you need to maintain that value through every iteration of the loop so that it is available when you need it again. You use a shift register for that purpose. If you don't need the reference in a particular event or case structure, you just need to make sure you wire it through the event/case from the left hand shift register node to the right hand shift register.
If you search for "state machine" in the forums, you should find numerous examples and discussions about it.
In case you haven't seen this, I would recommend looking at this. How to Learn LV
04-21-2009 01:18 PM - edited 04-21-2009 01:19 PM
It's no problem RavensFan.
I think you & Altenbach covered it (code review) quite well. The example I posted should give an idea ofhow to implement the code, which mostly goes to inside the consumer loop. I opted for the Queue because you can add more data items to it, if necessary. I didn't try to run it, so I do not know if it will run. I'm having a quick look at the forum between two meetings.
Vaibhav,
To learn more about LabVIEW, also I suggest you try looking at some of these tutorials.
R