Home AMX User Forum NetLinx Studio

WAIT_UNTIL in Modules?

Greetings,

I am using wait_until in a module. I am waiting until a variable brought in from the main module goes true. However, the module events occur whether or not the wait until statement is true.

I have heard that waits can misbehave in modules. Has anyone had similar experiences?

Thanks.

Comments

  • ericmedleyericmedley Posts: 4,177
    Greetings,

    I am using wait_until in a module. I am waiting until a variable brought in from the main module goes true. However, the module events occur whether or not the wait until statement is true.

    I have heard that waits can misbehave in modules. Has anyone had similar experiences?

    Thanks.

    Perhaps I'm not understanding the example...

    Are you saying you're waiting on a state change from a variable that is passed in your module from the DEFINE_MODULE statement?

    If so, that doesn't happen in runtime. It's not going to change state. Isn't that so? It get's passed in at startup and a wait_until won't happen.
  • DHawthorneDHawthorne Posts: 4,584
    I've not heard that, but neither have I tried it. I can't think of any reason why it wouldn't work, though. I wonder if the module handler makes all WAIT_UNTILs have an implicit timeout? You could test that, maybe, by putting an explicit timeout well past the time you need the wait to last ... as long as an implicit timeout doesn't override it.

    Another thought is that waits are treated very different than other operations ... in effect, the code is put in mainline, and therefore all referencing has to be persistent (which is why you can't have stack-vars in a wait). Perhaps something about the instancing feature of modules throws this off. But I have used standard waits in modules rather extensively for projector warmups and the like, without any difficulty.
  • ericmedleyericmedley Posts: 4,177
    DHawthorne wrote: »
    I've not heard that, but neither have I tried it. I can't think of any reason why it wouldn't work, though. I wonder if the module handler makes all WAIT_UNTILs have an implicit timeout? You could test that, maybe, by putting an explicit timeout well past the time you need the wait to last ... as long as an implicit timeout doesn't override it.

    Another thought is that waits are treated very different than other operations ... in effect, the code is put in mainline, and therefore all referencing has to be persistent (which is why you can't have stack-vars in a wait). Perhaps something about the instancing feature of modules throws this off. But I have used standard waits in modules rather extensively for projector warmups and the like, without any difficulty.

    To this point, I too have used waits in modules without ill effect. But typically they always reference things in the module. If I've needed to get some kind of value from the main program druing runtime, I pass it in as a command, channel state change or level and the handling of that value occurs in the module itself. I guess the idea is that I don't handle raw values from the main program without some kind of arbitor be that a virtual device state change or command that needs parsing.
  • mpullinmpullin Posts: 949
    After the discovery of a certain TCP/IP bug, I have started to define a variable to pass to all my IP modules called nINTERNET_ACCESS. If this variable is 0, the master is unable to access the internet, and all my IP modules know to stop attempting to look up hosts. It works fine. I am however not including this variable in a WAIT or WAIT_UNTIL. But I don't see why it wouldn't work.
  • Joe HebertJoe Hebert Posts: 2,159
    ericmedley wrote:
    Are you saying you're waiting on a state change from a variable that is passed in your module from the DEFINE_MODULE statement?

    If so, that doesn't happen in runtime. It's not going to change state. Isn't that so? It get's passed in at startup and a wait_until won't happen
    That?s not true, that?s not the way it works. The variables are passed in by reference, the main program and the module are pointing to the same thing. Change the variable in the main program and the module will see it. Change the variable in the module and the main program will see it.

    Also AFAIK WAITs and WAIT_UNTILs work fine in a module even when the UNTIL is based on a variable that?s passed into the module.

    Here is code and output that demonstrates that:

    Main Program:
    DEFINE_DEVICE
    
    dvTP = 10001:1:0
    
    vdvTest = 33001:1:0
    
    DEFINE_VARIABLE _
    
    VOLATILE INTEGER nVar1
    VOLATILE INTEGER nVar2
    
    DEFINE_START
    
    DEFINE_MODULE 'Module' mdl (vdvTest, nVar1,nVar2)
    
    DEFINE_EVENT
    
    BUTTON_EVENT[dvTP,1] {
    
       PUSH: {
          SEND_STRING 0,'PUSH 1'
          nVar1 = 1
       }
    }
    
    BUTTON_EVENT[dvTP,2] {
    
       PUSH: {
          SEND_STRING 0,'PUSH 2'
          PULSE[vdvTest,1]
       }
    }
    
    BUTTON_EVENT[dvTP,3] {
    
       PUSH: {
          SEND_STRING 0,'PUSH 3'
          nVar2 = 1
       }
    
    }
    

    Module:
    MODULE_NAME='Module' (DEV vdvTest,  INTEGER  nMainVar1, INTEGER nMainVar2)
    
    DEFINE_START
    
    WAIT_UNTIL (nMainVar1) {SEND_STRING 0,'nMainVar1 is TRUE'}
    
    DEFINE_EVENT
    
    CHANNEL_EVENT[vdvTest,1] {
    
       ON: {
       
          SEND_STRING 0, 'Starting WAIT_UNTIL'
          WAIT_UNTIL (nMainVar2) {SEND_STRING 0,'nMainVar2 is TRUE'}
       
       }
    
    }
    
    

    And the output when buttons 1, 2 and 3 are pushed.
    Line      1 :: PUSH 1 - 16:28:48
    Line      2 :: nMainVar1 is TRUE - 16:28:48
    Line      3 :: PUSH 2 - 16:28:50
    Line      4 :: Starting WAIT_UNTIL - 16:28:50
    Line      5 :: PUSH 3 - 16:28:54
    Line      6 :: nMainVar2 is TRUE - 16:28:54
    
    
  • TurnipTruckTurnipTruck Posts: 1,485
    I meant to say that the variable for the wait_until in the module is being passed in from the main program.
  • mpullin wrote: »
    After the discovery of a certain TCP/IP bug, I have started to define a variable to pass to all my IP modules called nINTERNET_ACCESS. If this variable is 0, the master is unable to access the internet, and all my IP modules know to stop attempting to look up hosts. It works fine. I am however not including this variable in a WAIT or WAIT_UNTIL. But I don't see why it wouldn't work.

    What bug are you referring to and how do you test if the controller has internet access?

    The reason i am asking is that i am experiencing controller lockups when internet is down....
    Thanks!
  • viningvining Posts: 4,368
    TT excuse the drift.

    Dries Kaspers wrote:
    how do you test if the controller has internet access?

    The simplest thing to do is ping a URL like AMX.com that resides on the internet or you could do something a little more useful and open a connection to http://www.amx.com/ip.asp and periodically retireve your public IP.

    If you want to try the ping approach try this:

    From: http://amxforums.com/showthread.php?t=377&highlight=pinging+master

    cwpartridge AMX Engineering wrote:
    Use IP_CLIENT_OPEN to url 'localhost' (i.e. 127.0.0.1) and port 23 (or the current Telnet port of the master). This will open a telnet session between the master and the NetLinx local port. Then using SEND_STRING you can issue a ping to an IP/URL using the telnet session to do the work. Use a DATA_EVENT to parse the return string response from the telnet session.

    If telnet security is on, NetLinx will be prompted to login and you will have to code an appropriate user and password to login with.

    Also remember that there is a limited number of telnet sessions the master will accept (current firmware is 4 but earlier versions were limited to 2).

    HTH,

    Chuck

    If you ping an address you should receive an "is Alive" response.
  • a_riot42a_riot42 Posts: 1,624
    Greetings,

    I am using wait_until in a module. I am waiting until a variable brought in from the main module goes true. However, the module events occur whether or not the wait until statement is true.

    I have heard that waits can misbehave in modules. Has anyone had similar experiences?

    Thanks.

    I haven't had any issues passing variables to a module or with the use of waits, but I would strongly suggest not using a wait_until in any code. It sounds like you are wanting to have something happen when a variable status changes so why not use a channel_event?
    You might want to post your code as well, since there may be something else going on.
    Paul
  • DHawthorneDHawthorne Posts: 4,584
    a_riot42 wrote: »
    I haven't had any issues passing variables to a module or with the use of waits, but I would strongly suggest not using a wait_until in any code. It sounds like you are wanting to have something happen when a variable status changes so why not use a channel_event?
    You might want to post your code as well, since there may be something else going on.
    Paul

    Oh, I wouldn't go that far. WAIT_UNTIL has some valid uses. For example, many new AV receivers need a few seconds to warm up before they will act properly on another command (like input changes). So I set a variable when they are turned on, wait 5 seconds (or whatever is needed), and then turn the variable off. In my source selection routine, I'll put a WAIT_UNTIL (flag is off) block with all my receiver commands. If the receiver is already on, it processes immediately, if it must be turned on, the appropriate delay occurs.It's much more elegant, in my view, than waiting no matter what, or putting a wait inside an IF statement, then having to repeat the source changes outside the if as well. If the warm up time is more than a few seconds, I'll also cancel the WAIT_UNTIL if another source is selected before it times out, so there isn't a rash of commands if the user is impatient. I do something similar with projectors, except I will also lock out additional commands until the thing is on or off, because the wait times are generally much longer.
  • ericmedleyericmedley Posts: 4,177
    Joe Hebert wrote: »
    That?s not true, that?s not the way it works... etc...

    Thanks for posting that. You don't know how long I've operated under that assumption. (years) I've always worked around it. It didn't stop me from using modules, I just communicated through virtual devices and/or command/strings.
  • mpullinmpullin Posts: 949
    What bug are you referring to and how do you test if the controller has internet access?

    The reason i am asking is that i am experiencing controller lockups when internet is down....
    Thanks!
    This bug has been reported but I don't know if anything has come of it yet:

    If you call IP_CLIENT_OPEN on an external address (e.g. 'weather.com'), and don't have an internet connection, the socket will attempt to do a DNS lookup, in vain, for maybe a dozen seconds. During this time packets sent to other TCP/IP sockets, even sockets on the local network such as your K-scape or Lutron, will be queued somehow, so that when the DNS lookup finally fails and quits, those other packets are all sent at once causing mayhem and/or lost information.

    Obviously all TCP/IP sockets should be independent. If one has a problem it should not affect every other socket!

    The workaround is to not attempt to request things from external sites if you don't have an internet connection. So I rewrote all my internet outreach modules to accept a parameter nINTERNET_ACCESS and never call IP_CLIENT_OPEN if the variable is false. I wrote an additional module to send a ping to a predictable, well known website every hour and if I don't get a response to the ping within a reasonable time, set nINTERNET_ACCESS to FALSE. Whenever it gets any response it sets nINTERNET_ACCESS to true and cancels the wait which would set nINTERNET_ACCESS to false.
  • ericmedleyericmedley Posts: 4,177
    mpullin wrote: »
    This bug has been reported but I don't know if anything has come of it yet:

    If you call IP_CLIENT_OPEN on an external address (e.g. 'weather.com'), and don't have an internet connection, the socket will attempt to do a DNS lookup, in vain, for maybe a dozen seconds. During this time packets sent to other TCP/IP sockets, even sockets on the local network such as your K-scape or Lutron, will be queued somehow, so that when the DNS lookup finally fails and quits, those other packets are all sent at once causing mayhem and/or lost information.

    Obviously all TCP/IP sockets should be independent. If one has a problem it should not affect every other socket!

    The workaround is to not attempt to request things from external sites if you don't have an internet connection. So I rewrote all my internet outreach modules to accept a parameter nINTERNET_ACCESS and never call IP_CLIENT_OPEN if the variable is false. I wrote an additional module to send a ping to a predictable, well known website every hour and if I don't get a response to the ping within a reasonable time, set nINTERNET_ACCESS to FALSE. Whenever it gets any response it sets nINTERNET_ACCESS to true and cancels the wait which would set nINTERNET_ACCESS to false.

    This might explain a problem I've had with the new Kaleidescape module. If the client's IP address changes on the their DSL modem (which interrupts thier internet connection for a short time) The K-Scape module goes nuts with runtime erros. (ON_ERROR, socket error, etc...) It only happens with their module. It's so bad it can bring down the master. The output light stays on solid.

    Most everything I do, I monitor and stop trying until the internet comes back. I do a similar thing as you do.

    I never put two and two together... thanx!
  • a_riot42a_riot42 Posts: 1,624
    DHawthorne wrote: »
    It's much more elegant, in my view, than waiting no matter what, or putting a wait inside an IF statement, then having to repeat the source changes outside the if as well.

    Not sure what you mean. Any device that needs a 'warm up wait' gets a wait iff it isn't on. If its already on then the input switch occurs with no wait.
    if ( ! [vdvRcvr, cnRcvr_PwrOn])
    {
      cancel_wait 'Rcvr Warm Up'
      do_push_timed(vdvRcvr, cnRcvr_PwrOn, 1)
      wait 50 'Rcvr Warm Up'
      {
        do_push_timed(vdvRcvr, cnRcvr_DVD, 1)
      }
    else
    {
      do_push_timed(vdvRcvr, cnRcvr_DVD, 1)
    }
    

    Etc...

    Paul
  • mpullinmpullin Posts: 949
    a_riot42 wrote: »
    if ( ! [vdvRcvr, cnRcvr_PwrOn])
    {
      cancel_wait 'Rcvr Warm Up'
      do_push_timed(vdvRcvr, cnRcvr_PwrOn, 1)
      wait 50 'Rcvr Warm Up'
      {
        do_push_timed(vdvRcvr, cnRcvr_DVD, 1)
      }
    else
    {
      do_push_timed(vdvRcvr, cnRcvr_DVD, 1)
    }
    

    I think what Dave is saying is that the block you just posted can be rewritten as:
    IF([vdvRcvr, cnRcvr_PwrOn] == FALSE) DO_PUSH_TIMED(vdvRcvr, cnRcvr_PwrOn, 1);
    WAIT_UNTIL([vdvRcvr, cnRcvr_PwrOn]) DO_PUSH_TIMED(vdvRcvr, cnRcvr_DVD, 1);
    
    In your scenario, if the receiver takes longer than 5 seconds to get warmed up you're screwed. IF you can get 100% reliable power state feedback, you can use a WAIT_UNTIL and there is no need to guess how much time would be safe to wait for it. That is a big IF though. Most of the time I end up doing what you do (the-wait-with-generous-guess-inside-if method).
  • a_riot42a_riot42 Posts: 1,624
    mpullin wrote: »
    In your scenario, if the receiver takes longer than 5 seconds to get warmed up you're screwed.

    True but it never does, unless there are bigger problems to worry about. They tend to be creatures of habit fortunately.
    mpullin wrote: »
    IF you can get 100% reliable power state feedback, you can use a WAIT_UNTIL and there is no need to guess how much time would be safe to wait for it. That is a big IF though. Most of the time I end up doing what you do (the-wait-with-generous-guess-inside-if method).

    The problem with the wait_until code is that you might need a delay between the time the unit is turned on, and when it will respond to the next command. In that case the wait_until will execute since the unit is being turned on, but it will send the second command too soon as the unit can't accept a command right after being turned on. So you need to wait some period of time after the unit has been turned on to be sure the second command is always sent after the power up self test.
    Paul
  • DHawthorneDHawthorne Posts: 4,584
    a_riot42 wrote: »
    True but it never does, unless there are bigger problems to worry about. They tend to be creatures of habit fortunately.



    The problem with the wait_until code is that you might need a delay between the time the unit is turned on, and when it will respond to the next command. In that case the wait_until will execute since the unit is being turned on, but it will send the second command too soon as the unit can't accept a command right after being turned on. So you need to wait some period of time after the unit has been turned on to be sure the second command is always sent after the power up self test.
    Paul

    No, you either use the feedback from the device (preferred, if available) to switch the flag the WAIT_UNTIL is waiting on, or you use another wait for the timer period to set that flag. I'll post a full code block later if I get the chance to clarify, but I need to run out the door in a minute.
  • a_riot42a_riot42 Posts: 1,624
    DHawthorne wrote: »
    No, you either use the feedback from the device (preferred, if available) to switch the flag the WAIT_UNTIL is waiting on, or you use another wait for the timer period to set that flag. I'll post a full code block later if I get the chance to clarify, but I need to run out the door in a minute.

    I understand that you are flipping a variable based on real feedback to end the wait_until. That seems reasonable but I choose not to use it since I think it can tend to lead to hard to find timing errors. I have nightmares of getting a call to fix a problem in code written by someone who loves wait_until:
    wait_until (isRcvrOn)
    {
      wait_until (isInputDVD)
      {
        wait_until (isDVDOn)
        {
          wait_until (isProjectorOn)
          {
            wait_until (isScreenDown)
            {
              startDVD()
            }
          }
        }
      }
    }
    
Sign In or Register to comment.