Home AMX User Forum NetLinx Studio

Function variable not working in waits..

So I'm having an issue with my online events for my touchpanels.

I always stack my TP online events and use DATA.DEVICE, or DATA.DEVICE.NUMBER to send all updates and flags to them. In this job we're using an Autonomic Mirage media server that has a UI module for each TP. In order to make sure the UI module will work correctly, I have to connect to the server, send a few commands, then close the connection when each TP comes online.

That involves three waits: wait to make sure TP is connected then connect to server, wait for connection to be established and then send my commands, and then wait for the replies and close the connection.

So, if the tp's came up one at a time, DATA.DEVICE works fine. During a reboot when they all come up about the same time, it seems that DATA.DEVICE is only the latest one that comes up in the stack. IE, some commands go out correctly, some go out twice to the same device, and usually only the last TP online gets everything.

So I put everything into a function and on the online event I did a "TP_ONLINE(DATA.DEVICE.NUMBER)"

Same results. It seems that as the function gets called over and over, the reference variable changes. I was under the impression that calling a function with waits blocked that code out and calling the same function again before the wait expired would block another set of functions out. I guess not.

If a function variable is passed by reference will "FUNCTION(REFERENCE)" change as often as the REFERENCE changes?

I'll try the function call with a index of the TP. FUNCTION(1) should always be different then FUNCTION(2) right?

Kevin D.

Comments

  • mpullinmpullin Posts: 949
    What about
    TP_ONLINE(DATA.DEVICE.NUMBER+0)
  • shr00m-dewshr00m-dew Posts: 394
    I can try that, but I'm not expecting it to work.
    DATA_EVENT[TPS]
    {
        ONLINE:
        {
        TP_ONLINE(GET_LAST(TPS))
        }
    }
    
    DEFINE_FUNCTION TP_ONLINE(INTEGER INDEX)
    {
        LOCAL_VAR LAST_DEVICE
    
        LAST_DEVICE=TPS[INDEX].NUMBER
    }
    

    Didn't work.

    And even
    DATA_EVENT[TPS]
    {
        ONLINE:
        {
        SWITCH (DATA.DEVICE.NUMBER)
        {
            CASE 10128:
            {
                TP_ONLINE(10128)
             }
        }
    }
    

    Didn't work either.

    The only thing that has worked is a seperate DATA_EVENT and code for each TP.

    Kevin D.
  • mpullinmpullin Posts: 949
    Neither of those examples show where the WAIT is involved. :-|
  • viningvining Posts: 4,368
    The functions should be called every time a TP comes online but only code block inside the wait will be skipped if the wait is pending. Since your passing by reference when the wait time expires and it's code block executes it will use what ever data.dev.number happens to be at that time which may be different from what it was when the function was initially called. Then depending on the wait times and the TPs coming online sometimes the wait will be ready and other times they will already be pending so it can be messy with varying results based on when things actually come online and the state of the waits when they do.

    If you want to trigger by the data.event online handler then I would probably create waits for each TP and pass the TPs index to the function and then switch case or select active the index with the different waits for each TP.
  • Spire_JeffSpire_Jeff Posts: 1,917
    The variables you are using are a specific space in memory and the value will only reflect the most recent data. You will probably have to do something like (or use separate events as you found):
    define_variable
    volatile integer nInitializeTp[MAX_NUM_TP];
    dev dvTPs[MAX_NUM_TP] = {dvTp1,dvTp2,...dvTpN}
    
    define_function doTpInitialize(integer nTpIndex){
       send_command dvMedia,"'TP_ONLINE=',itoa(nTpIndex)"; //Simulated command. Do what is necessary without delay.
    }
    define_function runTpUpdate(){
      local_var integer x;
      if(!x or x>MAX_NUM_TP)
         x=1;
      while(!nInitializeTP[x] and x <= MAX_NUM_TP)
         x++;
      if(x<=MAX_NUM_TP)
         wait 20 { //Adjust time between initializations accordingly.
           if(nInitializeTP[x]){
              doTpInitialize(x);
              nItnitializeTP[x] = 0;
           }
           x++;
           runTpUpdate();
         }
    }
    
    define_event
    data_event[dvTPs]{
      online:{
         nInitializeTP[get_last(dvTPs)] = 1;
         runTpUpdate();
      }
      offline:{
         nInitializeTP[get_last(dvTPs)] = 0;
         
      }
    }
    
    

    I think that will do what you need, but I have not checked for temporary lapses in logical thinking, nor temporary lapses in typing ability :)

    Jeff
  • shr00m-dewshr00m-dew Posts: 394
    Jeff,

    That probably would have worked. I wound up going with a timeline for every TP, but a stacked set of timeline events. The timeline ID's were the TP numbers, and commands sent to the TP's were based off of timeline.id.
    DATA_EVENT[TP_POOL]					
    {
    	ONLINE:
    	{
    		TIMELINE_CREATE(TP_POOL_TIMELINE, TP_TIMELINE_ARRAY, 3, TIMELINE_RELATIVE,TIMELINE_ONCE)
    	}
    	STRING:
    	{
    		SEND_COMMAND DATA.DEVICE.NUMBER+23000:1:1,"DATA.TEXT"
    	}
    }
    DATA_EVENT[TP_GARAGE]			
    {
    	ONLINE:
    	{
    		TIMELINE_CREATE(TP_GARAGE_TIMELINE, TP_TIMELINE_ARRAY, 3, TIMELINE_RELATIVE,TIMELINE_ONCE)
    	}
    	STRING:
    	{
    		SEND_COMMAND DATA.DEVICE.NUMBER+23000:1:1,"DATA.TEXT"
    	}
    }
    
    TIMELINE_EVENT[TP_POOL_TIMELINE]					
    TIMELINE_EVENT[TP_GARAGE_TIMELINE]
    {
    	LOCAL_VAR INTEGER nCount
    	
    	SWITCH(TIMELINE.SEQUENCE)
    	{
    		CASE 1:
    		{
    			SWITCH (M_TUNE_STATUS)
    			{
    				CASE 1:
    				{
    					SEND_COMMAND TIMELINE.ID:1:1,"'^TXT-31,0,'"
    				}
    				CASE 2:
    				{
    					SEND_COMMAND TIMELINE.ID:1:1,"'^TXT-31,0,Tuned'"
    				}
    			}
    			SWITCH (M_BAND)
    			{
    				CASE 1:
    				{
    					SEND_COMMAND TIMELINE.ID:1:1,"'^TXT-33,0,FM'"
    				}
    				CASE 2:
    				{
    					SEND_COMMAND TIMELINE.ID:1:1,"'^TXT-33,0,AM'"
    				}
    				CASE 3:
    				{
    					SEND_COMMAND TIMELINE.ID:1:1,"'^TXT-33,0,DAB'"
    				}
    				CASE 4:
    				{
    					SEND_COMMAND TIMELINE.ID:1:1,"'^TXT-33,0,XM'"
    				}
    			}
    			IF (LENGTH_STRING(M_FREQ_ASCII)>4)
    				SEND_COMMAND TIMELINE.ID:1:1,"'^TXT-32,0,',M_FREQ_ASCII[1],M_FREQ_ASCII[2],M_FREQ_ASCII[3],'.',M_FREQ_ASCII[4],M_FREQ_ASCII[5]"
    			ELSE
    				SEND_COMMAND TIMELINE.ID:1:1,"'^TXT-32,0,',M_FREQ_ASCII[1],M_FREQ_ASCII[2],'.',M_FREQ_ASCII[3],M_FREQ_ASCII[4]"
    			ON[TIMELINE.ID+23000:1:1,1]
    		}
    		CASE 2:
    		{
    			DO_PUSH(TIMELINE.ID:11:1,255)
    		}		
    		CASE 3:
    		{		
    			OFF[TIMELINE.ID+23000:1:1,1]
    			FOR(nCount = 1; nCount <= 24; nCount ++)
    			{
    				SEND_COMMAND TIMELINE.ID:4:1,"'^TXT-',ITOA(nCount+50),',0,',SA_TEXT[nCount]"
    	
    				IF (SA_TEXT[nCount]='Off')
    				{
    					SEND_COMMAND TIMELINE.ID:4:1,"'@SHO',nCount+100,0"
    					SEND_COMMAND TIMELINE.ID:4:1,"'^TXT-',ITOA(nCount),',0, '"
    				}
    				ELSE
    				{
    					SEND_COMMAND TIMELINE.ID:4:1,"'^TXT-',ITOA(nCount),',0,',ITOA(VOLUME[nCount])"
    				}
    			}
    			DO_PUSH(TIMELINE.ID:1:1,157)
    		}
    	}
    }
    
  • truetrue Posts: 307
    Create an array the length of the count of touchpanels, and create an array of touchpanels and abandon the stacking. Use the array for your data events. (It looks like you did this in your example.)

    When the panel is online, set the variable based on get_last() to a value, and start your wait. When your wait expires, have it loop / iterate through your variable and for each one it finds set to your value, perform the appropriate action, then clear the variable.

    To quickly modify an above example:
    define_constant
    TP_COUNT = 3
    
    define_variable
    volatile integer i  // generic non-blocked iterator used in waits
    volatile integer tp_status[TP_COUNT]
    volatile dev TPS[tp1, tp2, tp3]
    
    define_event
    DATA_EVENT[TPS] {
        ONLINE: {
            tp_status[get_last(TPS)] = 1
            TP_ONLINE()
        }
    }
    
    DEFINE_FUNCTION TP_ONLINE() {
        wait (30) {
            for (i = 1; i <= TP_COUNT; i++) {
                if(tp_status[i] == 1) {
                    // do what you want here
                    tp_status[i] = 0
                }
            }
        }
    }
    

    Of course, this starts the wait after the first touchpanel. Is there a real reason / need for the wait?
  • shr00m-dewshr00m-dew Posts: 394
    That would work as well..

    Reason for the waits is I don't want to rewrite the Autonomics module more than I already have. Using their module you can't discretely select a zone to control without first asking for available zones. That involves:

    Connecting the UI module to the server
    Wait for module to connect and be ready
    Pretend you're someone hitting the zone button to get a listing of zones
    Wait for the zone listing to return
    Disconnect the UI module from the server to kill unneeded traffic.

    It wouldn't be too hard to modify the module to hard code the zone names, but the end user easily has the ability to change those.

    Kevin D.
  • truetrue Posts: 307
    I already wrote an AppleTV module...maybe I should write something for whatever you are trying to control - but release it as open source and without limitations like these... ;)

    That company is going to hate me eventually.
  • shr00m-dewshr00m-dew Posts: 394
    Well, the product (now) performs as expected.

    The well known issues with not declaring huge variables as volatile is easy to fix. The use of slots for bitmaps I dealt with. The fact that it uses port zero for all keyboard functions wasn't hard to overcome (hence the string to string command).

    The biggest issue was that the 2.3 module on their website is for the media server software they sell and not for the Mirage stand-alone unit. It works great out of the box, good enough for us to spec it in a couple of jobs. It's when you get to the little details that things started falling apart.

    I got "that's addressed in our next module, coming out in two weeks". I started to feel like the money pit, every thing was coming in two weeks. I finally asked if I just need to rewrite the whole module, and that's when I was told the Mirage firmware didn't support everything the server software did and that a new firmware was needed in addition to the new module. That finally came two months after installation.

    So at this point I wish it used array's instead of having two modules for every TP in the system, but it works. The only issue left is deleting saved playlists. That command hasn't been implemented yet and I'm stuck with three 'TEST' playlists I created working through the modules. I'm promised that's coming in two weeks.. ;)

    If anyone wants my modified 2.4 module, I'll send it. 2.3 is still the latest on the site. I need to comment my changes (and send it back to them), but it's better then what comes from the website. It really need to be half the price and have some form of direct OSD control of one zone (that's coming in two weeks as well), but it does a lot of cool stuff as it is right now.

    Biggest changes are better memory management, truly working favorites (with option to delete(2.4 supported modules, but they didn't test it. At least 2.4 gave me the right commmands to make it work)), search for anything (not just the exact starting chars), better 'back' support, fixed the page +/- errors, and buttons to get available zones and then select a specific zone.

    The module is open source luckily, just so full of functions it's hard to follow what is going on. I would love for you to rewrite it, but the latest protocol document is for the server software and from 2007.....

    Kevin D.
Sign In or Register to comment.