Home AMX User Forum NetLinx Studio
Options

Using Variables in Wait Blocks... any good way to do it?

If I have the following code:
DEFINE_CALL 'POPUP_CONTROL' (INTEGER TP)
{
   SEND_COMMAND dvTPALL[TP],"'@PPN-PopUp;MainPage'"
}
.
.
.
DEFINE_EVENT[dvTPALL,btnPOPUP]
{
   PUSH:
   {
      LOCAL_VAR INTEGER I

      FOR(I=1;I<10;I++)
      {
         WAIT 10
         {
            CALL 'POPUP_CONTROL' (I)
         }
      }
   }
}
It will not execute for I=1 because once the wait executes, the loop for I will be at a different increment, and probably to I=11 already. This kinda stinks, because I might have a routine that shuts down a single zone, and I might want to shut down all the zones using a loop, but I can't do it with variables. Is there some trick to prevent this race condition with waits that I'm missing?

Thanks,

Pat

Comments

  • Options
    DHawthorneDHawthorne Posts: 4,584
    I don't see the need in that snippet for either the CALL or the FOR loop. Unless there is more to it than you are showing us, you could replace the line that makes the CALL with SEND_COMMAND dvTPALL,"'@PPN-PopUp;MainPage'". That will eliminate your WAIT issue becasue you are no longer referencing a variable in it. If you send a command out to an array of devices, all the devices in that array will get it.

    On general principle, I never create CALLs that are a single line long - you have to type a single line in to call it, why not just put that one line of code there? There are cases where it might be easier to update if separated out that way.

    Now, if you just simplified that CALL to post it, that's another story. In that case, I would make the actual DEV for the panel the argument for your CALL, and inside the WAIT do this: CALL 'POPUP_CONTROL' (dvTPALL). The value of I is resolved into an individual device before the CALL is made, so by the time the value of I changes, the CALL already took place.
  • Options
    alexanboalexanbo Posts: 282
    Well for your particular case I think if you swap the wait and the for statement so that the for loop is inside the wait it would probably work, well unless someone hammers the button and manages to somehow get a second button event to fire before the first wait finishes.
  • Options
    GasHedGasHed Posts: 31
    First, I greatly simplified the example... the actual call I have does quite a bit... and I don't necessary want to operated on a whole DEV array... I was just trying to simplify the code to focus on the real issue. You did answer my question with the last comment you made though. Pass the array element directly... I considered doing this, but it's not really convenient, and I'm not actually passing a device, but a zone number... Let me see if I can figure out a work around using the array idea... otherwise, I'll post a better example.

    Thanks much for the input!

    Pat
  • Options
    Spire_JeffSpire_Jeff Posts: 1,917
    Have you considered using a timeline? You could start the timeline with the button push and use the timeline.sequence variable as your I value. You could even create an array of integers that could be populated with nonsequential zone numbers (or whatever) that could be sent using ZONE_NUM[TIMELINE.SEQUENCE].

    Jeff
  • Options
    GasHedGasHed Posts: 31
    Considered yes... tried no... I see what you are saying. I'll give that a shot too.

    Pat
  • Options
    kphlightkphlight Posts: 10
    local or stack vars in a wait are generally a bad idea since they may not exist by the time the wait executes. You can get around this by adding another global variable (i.e. under define_variable) but the potential for a race condition still exists if you use that variable elsewhere.

    BTW, you are aware that all your waits will execute at approximately the same time? Use this to prevent that from happening:
    LOCAL_VAR INTEGER I
    
        if(non_local_var < 10) {  //prevents execution until all waits have passed
            non_local_var = 1
            FOR(I=1;I<10;I++) {
                wait 5 * i {
                    CALL 'POPUP_CONTROL' (non_local_var)
                }
            }
        }
    

    At the end of the call do:
    non_local_var++
    

    Note this only works if the call can complete execution in less than it takes for the next wait to begin (in the example above .5 seconds)
  • Options
    GasHedGasHed Posts: 31
    Some good observations kphlight... I was trying to think of a semiphore structure like you have, but the brain wasn't functioning well. And yes, I did realize that for my example all wait were about the same... my original code looked like yours... with the loop variable in the wait statement.

    Increment the global var at the end of the subroutine... really smart workaround ;)

    Pat
  • Options
    DHawthorneDHawthorne Posts: 4,584
    GasHed wrote:
    First, I greatly simplified the example... the actual call I have does quite a bit... and I don't necessary want to operated on a whole DEV array... I was just trying to simplify the code to focus on the real issue. You did answer my question with the last comment you made though. Pass the array element directly... I considered doing this, but it's not really convenient, and I'm not actually passing a device, but a zone number... Let me see if I can figure out a work around using the array idea... otherwise, I'll post a better example.

    Thanks much for the input!

    Pat
    I thought that may be the case. There is a simple answer to that too. Create a CONSTANT array with your zone numbers in it. Then pass an element of that array instead of the device. The CALL can then use that for an index to it's DEV array..
Sign In or Register to comment.