Home AMX User Forum NetLinx Studio

How to place individual WAITs on stack without defining them separately

Hello everyone. The best way I can think of to explain my question is with some pseudo-code that doesn't seem to work.

In the example below, I was assuming that each time the makeItemWait() function was called, it would place a new WAIT on the stack with a reference to the specific _myStruct that was passed to it when the function was called... Unfortunately, I tried something like this and was unsuccessful. I didn't see any errors, but I also didn't see the expected results.

Does anyone have any ideas for how to accomplish this without defining a separate WAIT for each item in the array? I would also love an explanation for why this doesn't work to better understand how NetLinx works.

structure _myStruct
{
    integer isWaiting;
}

_myStruct MyItem[32];

define_function makeItemWait(_myStruct item)
{
    item.isWaiting = 1;
    wait(50)
        item.isWaiting = 0;
}

button_event[dvTP,1]
button_event[dvTP,2]
button_event[dvTP,3]
{
    push:
    {
        stack_var integer c;
        c = button.input.channel;

        if(MyItem[c].isWaiting)
        {
            //do nothing
        }
        else
        {
            //do something here...
                
            //don't allow this block to be repeated until wait expires
            makeItemWait(MyItem[c]);
        }
    }
}

Comments

  • GregGGregG Posts: 251
    These 2 lines in your code comprise an "unnamed wait":
    wait(50)
      item.isWaiting = 0;
    

    It can only be added one time to the wait list, based on location in code and the code within.

    This is why/how the old mainline blinking code used to work:
    DEFINE_PROGRAM
    Wait 5
      nBlink=!nBlink
    

    If it added a new instance of nBlink=!nBlink every time through mainline, then after .5 seconds it would be the same as not having the wait at all.

    To get around this kind of problem, I usually use timelines like this:
    DEFINE_CONSTANT
    // Make sure you have one of these for each display, and they need to be sequential
    TL_MONITOR_1_POWER        =    21        
    TL_MONITOR_2_POWER        =    22
    TL_MONITOR_3_POWER        =    23
    TL_MONITOR_4_POWER        =    24
    TL_MONITOR_5_POWER        =    25
    TL_MONITOR_6_POWER        =    26
    TL_MONITOR_7_POWER        =    27
    TL_MONITOR_8_POWER        =    28
    TL_MONITOR_9_POWER        =    29
    TL_MONITOR_10_POWER        =    30
    // and record the base timeline ID-1
    TL_BASE    =    20 // the function will add Unit# to this later
    
    Define_Function DelayInput(Integer nMonitor, Long lTime, Integer nInput)
    {
        // Just in case:
        If(Timeline_Active(TL_BASE+nMonitor))
            Timeline_Kill(TL_BASE+nMonitor)
    
        lTimes[1] = lTime
        nMonitorInputs[nMonitor] = nInput
        Timeline_Create(TL_BASE+nMonitor,lTimes,1,TIMELINE_RELATIVE,TIMELINE_ONCE)
    }
    
    DEFINE_EVENT
    
    Button_Event[dvTP,100] // Monitor 10 to Input 1
    {
        Push:
        {
            Send_String dvMonitor10,'PON'
            // Wait 15 seconds before sending the input
            DelayInput(10,15000,1)
        }
    }
    
    // Timeline event triggers for the delayed input commands (stack all the constants from above in here)
    Timeline_Event[TL_MONITOR_1_POWER]
    Timeline_Event[TL_MONITOR_2_POWER]
    Timeline_Event[TL_MONITOR_3_POWER]
    Timeline_Event[TL_MONITOR_4_POWER]
    Timeline_Event[TL_MONITOR_5_POWER]
    Timeline_Event[TL_MONITOR_6_POWER]
    Timeline_Event[TL_MONITOR_7_POWER]
    Timeline_Event[TL_MONITOR_8_POWER]
    Timeline_Event[TL_MONITOR_9_POWER]
    Timeline_Event[TL_MONITOR_10_POWER]
    {
    Stack_Var Integer nMonitor
        nMonitor = timeline.id-TL_MONITOR_BASE_POWER
    
        // Do your thing here with nMonitorInputs[nMonitor]
    }
    

    If Timeline_Event[0] would work I could make this into a universal module, but last time I checked it didn't. ;-)
  • ericmedleyericmedley Posts: 4,177
    I would suggest changing the approach a bit. I can paraphrase your request like this:

    How can I make a series of waits of length X at any given time Y. I want it to be completely dynamic and universal.

    Perhaps what you need is a queue.

    For the example I'll say the wait is always going to be in tenths of a second.

    Make a repeating timeline that ticks at tenths of a second.

    Make the timeline have a "Kill" switch that stops it when the queue is done running.

    When you need to use it, start the timeline and create a counter that ticks how many tenths of a second have passed since the TL started. (there is already a timeline.repetition available for use if you want that.)

    create an array that will store each wait's information. You'll need to deal with the following:
    1) a method of getting the current tick count that will be used as a time stamp.
    2) a method to calculate the future time you want the event to fire.
    3) a way to store what it is you want to do when the event fires.
    4) a counter to store the number of things still in the queue needing to fire.

    So when you want to queue up a "wait" you grab where the timeline is currently at. (at the start it might be at time tick 1. if it's already running it might be something like time tick 241 (24 seconds and a tick - whatever)

    You then do the math on how long you want your wait to be. If it's 2 seconds from now, you ad 20 ticks to the current time and then store it in the queue.

    within the timeline you quickly run through your array and see if anything needs to fire right now. If so, you fire it off, decrement the queue size counter, check to see if the queue size counter is down to zero (if we are all done) and if so, kill the timeline. If not, keep going.

    That's how I do the kind of thing you're describing. It's very efficient and dynamic. You can actually change the time of a wait while in progress by simply changing the fire time in the array or whatever.
Sign In or Register to comment.