Home AMX User Forum NetLinx Studio

Get_Last alternatives

jjamesjjames Posts: 2,908
Just curious . . . for those of you who don't use GET_LAST, what's your poison? I can think of two different ways of handling it; the first would be using BUTTON.INPUT.CHANNEL, and the other would have button events for every single button, one for volume up, one for volume down, etc, etc.

So - in true open forum fashion, what do you do? No need to jump immediately into the efficiency debate, let's hear (read) what you use first - THEN debate. :D Feel free to post some watered-down code or at least a description to what you use, and why.

Remember, there IS NO wrong way of doing something here . . . unless of course you insist on using GET_LAST in a TIMELINE_EVENT. ;)
«13

Comments

  • ericmedleyericmedley Posts: 4,177
    I use the Button.input.channel method. I also get the device/port/system as well of the thing that's causing the event. It is precisely the 'TImeline' issue that I choose this method. It requires no more or less effort. And... can't a Get_Last be fooled if another button event happens between the time something is going on?
  • ColzieColzie Posts: 470
    I use both get_last and button.input.channel. I only use get_last for things that require common actions, such as source selection.
    (*********************************************)
    (* INFO: Source selection                    *)
    (*                                           *)
    (*********************************************)
    button_event[dv_TPs, WATCH_BTNS]
    {
    	push:
    	{
    		i_index_watch = get_last (WATCH_BTNS)
    		fn_activate_source (i_index_watch)
    	}
    }
    
    
    (*********************************************)
    (* INFO: Manual screen control               *)
    (*                                           *)
    (*********************************************)
    button_event[dv_TPs, SCREEN_DN]
    button_event[dv_TPs, SCREEN_UP]
    {
    	push:
    	{
    		switch(button.input.channel)
    		{
    			case SCREEN_DN:	fn_screen (SET_PWR_ON)
    			case SCREEN_UP:	fn_screen (SET_PWR_OFF)
    		}
    	}
    }
    
  • Jimweir192Jimweir192 Posts: 502
    Well it's a mixture of both for different applications.

    I was trying to think of 2 good examples for each option (get_last & b.i.c), but my brain is slow today and the best I can do is it depends on the maths I might be doing within the event...

    I don't think I've done individual button events since I first worked with Netlinx, apart from during device testing / debug...
  • jjamesjjames Posts: 2,908
    I try to exclusively use either GET_LAST, or single button events (i.e. DV_TP,nPWR_OFF), I haven't used B.I.C. in quite a while. On occasion I'll throw in some code that I know works and it's using B.I.C. and won't put in any effort to change it, but that's rare. I do think it's time I need to rethink my way of coding though; it's good to update it from time to time and try new things.
  • Spire_JeffSpire_Jeff Posts: 1,917
    About the only time I use single button events is when using an array of buttons results in my having to create a Switch..Case type implementation. I don't always use single events, but most of the time I go with single events because of two reasons: 1. Less work the processor has to do (no Switch statement) 2. I can collapse code to make it easier to view and modify.

    Jeff

    P.S.
    I use Get_Last a lot because I need an indexed value of the push. It just makes the math easier :)
  • I occasionally just use button.input.channel (I call it BUTTICH ;-) for simple one-off stuff. But 90+% of the time, I have a good reason to use GET_LAST() and indexing.
  • ericmedleyericmedley Posts: 4,177
    The main reason I dont' like the Get_last is that there is room for error in index the buttons.

    For example let's say you have a button array like this

    nButtons={1,2,3,5,6}

    example:
    BUTTON_EVENT[dev_TP_1,nBUTTONS]
    {
    PUSH:
      {
      nTP_Button_pushed_BIC=BUTTON.INPUT.CHANNEL
      nTP_Button_pushed_GL=get_last(nButtons)
      // DO SOMETHING
      }
    }
    

    Now, if you hit button 5 on the touch panel, nTP_Buttonpushed_BIC will equal 5 but nTP_Button_pushed_GL will equal 4 since the number 5 happens 4th on the list. I find the numeric data more advantageous than where it falls in my array order. I just choose my TP button numbers accordingly. for transport controls, I just tend to make the button numbers match up with the IR file or setup my serial commands in the same order as the AMX standard for transports.

    If I have an enormous button array, I don't want to do the counting on my fingers and toes to figure out where button 367 actually falls in the list of buttons.
  • glr-ftiglr-fti Posts: 286
    Interesting discussion. I hadn't really thought about what I do or why before. As I think about it I seem to use Get Last only when I am trying to find out what touch panel was used. Otherwise I use button.input.channel.
  • jjamesjjames Posts: 2,908
    Eric,

    I see where you're going with that, and once you mentioned BIC to IR mapping, it reminded me, I do that as well. I use GET_LAST for things such as source selection, camera selection, room selection, any type of selection really. But for straight through commands, I will use BIC. I do agree, it is much easier to do SEND_COMMAND dvDEVICE,"'SP',BUTTON.INPUT.CHANNEL" than mapping it all out in arrays.
  • Spire_JeffSpire_Jeff Posts: 1,917
    This all got me to thinking. If GET_LAST is really that bad, why not just write a function that simulates GET_LAST? Here is one that should work for an array of channels: (I even added one that lets you set an offset :) )
    DEFINE_FUNCTION INTEGER myGetLast(INTEGER nCHANNEL, INTEGER nARRAY[]){
    	STACK_VAR INTEGER x;
    	STACK_VAR INTEGER y;
    	y=LENGTH_ARRAY(nARRAY);
    	FOR(x=1;x<=y;x++){
    		IF(nCHANNEL == nARRAY[x])
    			RETURN x;
    	}
    	RETURN 0;
    }
    DEFINE_FUNCTION INTEGER myGetLastOffset(INTEGER nCHANNEL, INTEGER nARRAY[],INTEGER nOFFSET){
    	STACK_VAR INTEGER x;
    	STACK_VAR INTEGER y;
    	y=LENGTH_ARRAY(nARRAY);
    	FOR(x=1;x<=y;x++){
    		IF(nCHANNEL == nARRAY[x])
    			RETURN (x+nOFFSET);
    	}
    	RETURN 0;
    }
    

    You could also write one that works for devices:
    DEFINE_FUNCTION INTEGER myGetLastDev(DEV nCHANNEL, DEV nARRAY[]){
    	STACK_VAR INTEGER x;
    	STACK_VAR INTEGER y;
    	y=LENGTH_ARRAY(nARRAY);
    	FOR(x=1;x<=y;x++){
    		IF(nCHANNEL.NUMBER == nARRAY[x].NUMBER and 
    				nCHANNEL.PORT == nARRAY[x].PORT and 
    				nCHANNEL.SYSTEM == nARRAY[x].SYSTEM)
    			RETURN x;
    	}
    	RETURN 0;
    }
    

    You would have to call the correct function, but at least you could call them from everywhere in code without worrying. Unless I am not thinking clearly here (which is very possible). For some reason, the above just seems too simple. I wonder if it's because GET_LAST is overloaded????

    Jeff
  • TonyAngeloTonyAngelo Posts: 315
    Spire_Jeff wrote: »
    This all got me to thinking. If GET_LAST is really that bad,

    Did I miss something? What's wrong with Get_Last?
  • Joe HebertJoe Hebert Posts: 2,159
    TonyAngelo wrote: »
    Did I miss something? What's wrong with Get_Last?
    My thoughts exactly. I've never had a problem with GET_LAST and I use it all the time.
  • Spire_JeffSpire_Jeff Posts: 1,917
    I think the problem is one that manifests itself only occasionally and only in certain circumstances (namely in HOLDs if I recall correctly). I use it all the time myself, but given that there have been a few documented situations in which its use is not recommended, I've been thinking about switching.

    Jeff

    P.S.
    I was only able to find documentation in technotes about problems with GET_LAST being used in level events for the devices. I do know that there is also a problem with Holds.
  • Joe HebertJoe Hebert Posts: 2,159
    ericmedley wrote:
    The main reason I dont' like the Get_last is that there is room for error in index the buttons.
    I don?t want to sound argumentative (not that it?s ever stopped me before :) ) but there is no room for error in the index of buttons. Using your code as an example:
    nButtons={1,2,3,5,6}
    
    BUTTON_EVENT[dev_TP_1,nBUTTONS]
    {
    PUSH:
      {
      nTP_Button_pushed_BIC=BUTTON.INPUT.CHANNEL
      nTP_Button_pushed_GL=get_last(nButtons)
      // DO SOMETHING
      }
    }
    
    get_last(nButtons) does not and is not supposed to return the button number that was pushed, it returns the index of the array. If you want to use GET_LAST to get the actual button that was pushed you would need to change:
    nTP_Button_pushed_GL=get_last(nButtons)
    to:
    nTP_Button_pushed_GL=nButtons[get_last(nButtons)]
    which is just the long way around of saying:
    BUTTON.INPUT.CHANNEL

    There is nothing wrong with GET_LAST itself, just as there is nothing wrong with BUTTON.INPUT.CHANNEL. In your case if you want the actual button number to dictate how the code runs then BUTTON.INPUT.CHANNEL is the most direct route. GET_LAST and BUTTON.INPUT.CHANNEL are two completely different animals. Which one to ride all depends on where you want to go. I?m not suggesting that you (or anyone else) should use GET_LAST; my only point is that there is nothing wrong with it when used correctly.
    ericmedley wrote:
    I find the numeric data more advantageous than where it falls in my array order. I just choose my TP button numbers accordingly. for transport controls, I just tend to make the button numbers match up with the IR file or setup my serial commands in the same order as the AMX standard for transports.
    I personally find that too restricting. I normally choose to take the opposite approach and would rather setup a simple mapping scheme instead of tying myself to the actual TP button numbers themselves. I prefer to use the index of the array (therefore I use GET_LAST) as a pointer to the data I actually want to use. It?s a little more work but I find it to be more flexible. I do something like the following:
    DEFINE_DEVICE
    
    dvCable= 5001:9:0
    dvTP	= 10001:1:0
    
    DEFINE_CONSTANT
    
    INTEGER nCableButtons[] = {
       100,101,102,103,104,110,112
    }
    
    INTEGER nCableMap[] = {
    
       1,	// Play		//1	//100
       2,	// Stop		//2	//101
       3,	// Pause	//3	//102
       6,	// FFwd		//4	//103
       7,	// Rev		//5	//104
      51,	// Instant Reply//6	//110
       8	// Record	//7	//112
                                      
    }
    
    DEFINE_EVENT
    
    BUTTON_EVENT[dvTp,nCableButtons] {
    
       PUSH: {
          //pushing TP button 110 will send out IR code 51 - Instant Replay
          SEND_COMMAND dvCable,"'SP',nCableMap[GET_LAST(nCableButtons)]"
       }
    }
    
    Using this approach I don?t need to care what the actual TP buttons are and I can change, add, or remove as I please. The TP buttons don?t have to be consecutive; I can use whatever is available for the job.

    Again, I?m not suggesting you are anyone should take this approach; I?m simply offering an alternative. I can certainly see cases where the button numbers can be used to drive the code but that?s not my natural instinct.
  • Joe HebertJoe Hebert Posts: 2,159
    GET_LAST
    Spire_Jeff wrote:
    I was only able to find documentation in technotes about problems with GET_LAST being used in level events for the devices.
    I think that tech note is out of date. I can?t speak from first hand experience as I haven?t tested it yet but I believe that issue has been resolved for a while now.
    Spire_Jeff wrote:
    I do know that there is also a problem with Holds.
    A HOLD is a type of WAIT, therefore all bets are off if using GET_LAST in that instance.

    I wonder why GET_LAST is getting such a bad rap recently, it?s such a friendly little function that faithfully does what it?s supposed to do. I?ll stick by your side GET_LAST. :)
  • PetarPetar Posts: 14
    Interesting that a question from my side, leads to a discussion of the use of GET_LAST :)
  • viningvining Posts: 4,368
    Joe Hebert wrote:
    I wonder why GET_LAST is getting such a bad rap recently, it?s such a friendly little function that faithfully does what it?s supposed to do. I?ll stick by your side GET_LAST.
    I Concur!
  • ericmedleyericmedley Posts: 4,177
    Joe Hebert wrote: »
    The TP buttons don?t have to be consecutive; I can use whatever is available for the job.


    I agree, I haven't said there's anything wrong with using get_last. In fact, my post is somewhat in defense of your statement. I've heard people on this forum more-or-less say that it's (using get_last)the only accepted way of setting up and manipulating a button array.

    I just don't personally use it myself. It's just the way I organize things.

    Also, I quoted the text above to make the statement that you don't have to have consecutive buttons if you choose to use the BIC method. They can be in any order you with and in no particular grouping. I don't know if that's what you were implying. So, if not, then ignore this comment.

    :)
  • jjamesjjames Posts: 2,908
    I've used the scheme that you use in the past; and to be honest, I felt that it was too cumbersome and convoluted. That's not to say that I would NEVER use something like that again, but . . . I don't know. When I think of button number 22, I think of channel up, and 26 - I think of mute. 44? Menu. It's just a habit of mine I guess. I can definitely see the advantage of it, but it was too much of a pain to jump back and forth and look at things, looking for the channel and then looking for which IR code it's spitting out.

    I guess I sometimes like the straight through kind of code over the this-leads-to-this-leads-to-this type of code. But, every situation calls for something different. :D
  • Spire_JeffSpire_Jeff Posts: 1,917
    I forgot to pose this question last night as I wrote the functions, but I was wondering what would happen if someone accidentally created a button array that has multiple instances of the same value. In my functions, given multiple occurrences of the same value, the index of the first position of occurrence would be returned. I was wondering if GET_LAST did something different or if it was just an overloaded version of my functions. I thought it might create multiple events that get triggered, but I wasn't sure. I wrote this chunk of code to test it:
    DEFINE_CONSTANT
    INTEGER nUSER_BTN_TEST[] = {1,2,3,4,1,2,3,4,5,1,1,2,3,4,6}
    
    DEFINE_EVENT
    BUTTON_EVENT[dvTEST,nUSER_BTN_TEST]{
    	PUSH:{
    		LOCAL_VAR INTEGER x;
    		x++;
    		SEND_STRING 0,"'Button Push:',ITOA(BUTTON.INPUT.CHANNEL),' Iteration:',ITOA(x),' Get_Last:',ITOA(GET_LAST(nUSER_BTN_TEST))";
    	}
    	HOLD [3,REPEAT]:{
    		LOCAL_VAR INTEGER x;
    		x++;
    		SEND_STRING 0,"'Button Hold:',ITOA(BUTTON.INPUT.CHANNEL),' Iteration:',ITOA(x),' Get_Last:',ITOA(GET_LAST(nUSER_BTN_TEST))";
    	}
    	RELEASE:{
    		LOCAL_VAR INTEGER x;
    		x++;
    		SEND_STRING 0,"'Button Release:',ITOA(BUTTON.INPUT.CHANNEL),' Iteration:',ITOA(x),' Get_Last:',ITOA(GET_LAST(nUSER_BTN_TEST))";
    	}
    
    }
    
    

    As I expected, emulating a push on channel 1 generated 4 PUSH: events and 4 RELEASE: events. The thing that was interesting to me was the HOLD: Events. Only one instance of a HOLD: is created which reveals the correlation between HOLDs and WAITs. Here is the output generated by a push:

    Line 13 (10:40:28):: CIpHold::AddHold - Duplicate
    Line 14 (10:40:28):: CIpHold::AddHold - Duplicate
    Line 15 (10:40:28):: Button Push:2 Iteration:5 Get_Last:2
    Line 16 (10:40:28):: Button Push:2 Iteration:6 Get_Last:2
    Line 17 (10:40:28):: Button Push:2 Iteration:7 Get_Last:2
    Line 18 (10:40:28):: Button Hold:2 Iteration:2 Get_Last:2
    Line 19 (10:40:29):: Button Hold:2 Iteration:3 Get_Last:2

    I posted this info simply because I wanted to know how things happened and I decided to share the results in the slim chance that someone might find it enlightening or even interesting :)

    Jeff
  • Alright, let me see if I'm gathering all of this correctly:

    BUTTON.INPUT.CHANNEL is superior in the sense that it is, from a programmer's perspective, the most secure of the two options. The downside is that the codes cannot therefore be changed in some more organized constant; all such changes must be made in code, and made sure not to be upsetting anything.

    GET_LAST() is superior in that it allows for a greater amount of organizational control. Additionally, if it's method is fully understood, than there's virtually nothing which can be accomplished via the alternative option. It, however, has two potential downfalls: First being that it's the only overloaded function (I think) within all of Netlinx code, and therefore has in its peculiar function the likeliness to be less reliable. Secondly, there runs the issue that it cannot (or becomes vulnerable to not) function correctly in such things as WAITS, TIMELINES, and HOLDS.

    Obviously, if one understands the limit of both, then solid programming can come from either direction. Still, I'm very interested if Spire_Jeff's concept of creating a function to otherwise avoid the overloading issue would be a feasible solution to the whole "problem."

    I personally use "GET_LAST" a great deal, and have had no immediate problems - so long as I don't assume it to do something it doesn't, or push it to its logical limitations. Still, if it could be made to be more secure by writing one's own function to handle it all, then awesome. What do y'all think?
  • DHawthorneDHawthorne Posts: 4,584
    Alright, let me see if I'm gathering all of this correctly:

    BUTTON.INPUT.CHANNEL is superior in the sense that it is, from a programmer's perspective, the most secure of the two options. The downside is that the codes cannot therefore be changed in some more organized constant; all such changes must be made in code, and made sure not to be upsetting anything.

    GET_LAST() is superior in that it allows for a greater amount of organizational control. Additionally, if it's method is fully understood, than there's virtually nothing which can be accomplished via the alternative option. It, however, has two potential downfalls: First being that it's the only overloaded function (I think) within all of Netlinx code, and therefore has in its peculiar function the likeliness to be less reliable. Secondly, there runs the issue that it cannot (or becomes vulnerable to not) function correctly in such things as WAITS, TIMELINES, and HOLDS.

    Obviously, if one understands the limit of both, then solid programming can come from either direction. Still, I'm very interested if Spire_Jeff's concept of creating a function to otherwise avoid the overloading issue would be a feasible solution to the whole "problem."

    I personally use "GET_LAST" a great deal, and have had no immediate problems - so long as I don't assume it to do something it doesn't, or push it to its logical limitations. Still, if it could be made to be more secure by writing one's own function to handle it all, then awesome. What do y'all think?

    All these shortcomings can be simply overcome by either assigning your result from GET_LAST() or the contents of BUTTON.INPUT.CHANNEL to a variable and sending that to your function. No alternatives are needed.
  • DHawthorne wrote: »
    All these shortcomings can be simply overcome by either assigning your result from GET_LAST() or the contents of BUTTON.INPUT.CHANNEL to a variable and sending that to your function. No alternatives are needed.

    Well, in actuality, that's presently what I do, which satisfies most of the problems. Still, GET_LAST does have somewhat of an overload to it, which in Netlinx is worthy of a raised eyebrow. And while this works fine in the instance of a WAIT statement, it doesn't fix the issue of GET_LAST causing problems in HOLD events - which, admittedly, I've never had problems with, but I hear when it does happen it is in fact worse than a sharp stick in the eye.
  • Spire_JeffSpire_Jeff Posts: 1,917
    DHawthorne wrote: »
    All these shortcomings can be simply overcome by either assigning your result from GET_LAST() or the contents of BUTTON.INPUT.CHANNEL to a variable and sending that to your function. No alternatives are needed.

    I think that the HOLD problem with GET_LAST() will still exist even if you assign it to a variable. The problem arises in HOLD events because they are more like WAITs. The problem will only manifest itself if you are in the middle of a hold event on one panel and a user on a different panel pushes a button from the same array as I recall.

    Jeff
  • ericmedleyericmedley Posts: 4,177
    Spire_Jeff wrote: »
    I think that the HOLD problem with GET_LAST() will still exist even if you assign it to a variable. The problem arises in HOLD events because they are more like WAITs. The problem will only manifest itself if you are in the middle of a hold event on one panel and a user on a different panel pushes a button from the same array as I recall.

    Jeff


    I think too that if you use a local variable this creates the problem with the hold/wait/etc...


    I always go ahead and store the BIC values in a regular variable array, tag that particular event with a 'serial number' of sorts that identifies the cell in the array and then retire that cell once it's done. That way the data never gets interupted by another event happening. It's not like it's a big memory hog or something. It's just an integer.

    I have to admit, that's been confusing me in this discussion: not knowing why things get lost once you do a hold or wait or timeline... I got it this morning. If you use this method it's a non-issue.
  • Spire_JeffSpire_Jeff Posts: 1,917
    Ok, here are a couple more interesting things on this (at least to me :) ):

    First, I had to modify the myGetLastDev function slightly to account for devices declared with a system of 0. Here are the new functions:
    DEFINE_FUNCTION INTEGER myGetLast(INTEGER nCHANNEL, INTEGER nARRAY[]){
    	STACK_VAR INTEGER x;
    	STACK_VAR INTEGER y;
    	y=LENGTH_ARRAY(nARRAY);
    	FOR(x=1;x<=y;x++){
    		IF(nCHANNEL == nARRAY[x])
    			RETURN x;
    	}
    	RETURN 0;
    }
    DEFINE_FUNCTION INTEGER myGetLastDev(DEV nCHANNEL, DEV nARRAY[]){
    	STACK_VAR INTEGER x;
    	STACK_VAR INTEGER y;
    	y=LENGTH_ARRAY(nARRAY);
    	FOR(x=1;x<=y;x++){
    		IF(nCHANNEL.NUMBER == nARRAY[x].NUMBER and 
    				nCHANNEL.PORT == nARRAY[x].PORT and 
    				(nCHANNEL.SYSTEM == nARRAY[x].SYSTEM or (!nARRAY[x].SYSTEM and nCHANNEL.SYSTEM == GET_SYSTEM_NUMBER()))
    			)	
    			RETURN x;
    	}
    	RETURN 0;
    }
    

    Here is the test code I used to try this out. I am using DO_PUSH_TIMED to simulate other buttons being pushed during a hold:
    DEFINE_DEVICE
    dvTEST1	= 		10001:1:0;
    dvTEST2	=	 	10002:1:1;
    dvTEST3	=	 	10003:1:0;
    dvTEST4	=	 	10004:1:1;
    dvTEST5	=	 	10005:1:0;
    
    DEFINE_CONSTANT
    INTEGER nUSER_BTN_TEST[] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15}
    
    DEFINE_EVENT
    BUTTON_EVENT[dvTPs,nUSER_BTN_TEST]{
    	PUSH:{
    		LOCAL_VAR INTEGER x,y;
    		x = GET_LAST(dvTPs);
    		y = GET_LAST(nUSER_BTN_TEST);
    		SEND_STRING 0,"'###############################################################################'";
    		SEND_STRING 0,"'|[PUSH:]'";
    		SEND_STRING 0,"'| GET_LAST() -Dev:',ITOA(GET_LAST(dvTPs)),' Actual Dev:',
    										ITOA(BUTTON.INPUT.DEVICE.NUMBER),':',ITOA(BUTTON.INPUT.DEVICE.PORT),':',ITOA(BUTTON.INPUT.DEVICE.SYSTEM),
    										' | Actual Button Push:',ITOA(BUTTON.INPUT.CHANNEL),' Get_Last Index:',ITOA(GET_LAST(nUSER_BTN_TEST))";
    		SEND_STRING 0,"'| Variable() -Dev:',ITOA(x),' Actual Dev:',
    										ITOA(BUTTON.INPUT.DEVICE.NUMBER),':',ITOA(BUTTON.INPUT.DEVICE.PORT),':',ITOA(BUTTON.INPUT.DEVICE.SYSTEM),
    										' | Actual Button Push:',ITOA(BUTTON.INPUT.CHANNEL),' Get_Last Index:',ITOA(y)";
    		SEND_STRING 0,"'|       my() -Dev:',ITOA(myGetLastDev(BUTTON.INPUT.DEVICE,dvTPs)),' Actual Dev:',
    										ITOA(BUTTON.INPUT.DEVICE.NUMBER),':',ITOA(BUTTON.INPUT.DEVICE.PORT),':',ITOA(BUTTON.INPUT.DEVICE.SYSTEM),
    										' | Actual Button Push:',ITOA(BUTTON.INPUT.CHANNEL),' myGetLast Index:',ITOA(myGetLast(BUTTON.INPUT.CHANNEL,nUSER_BTN_TEST))";
    	}
    	HOLD [20,REPEAT]:{
    		LOCAL_VAR INTEGER x,y;
    		x = GET_LAST(dvTPs);
    		y = GET_LAST(nUSER_BTN_TEST);
    		SEND_STRING 0,"'*******************************************************************************'";
    		SEND_STRING 0,"'|[HOLD:]'";
    		SEND_STRING 0,"'| GET_LAST() -Dev:',ITOA(GET_LAST(dvTPs)),' Actual Dev:',
    										ITOA(BUTTON.INPUT.DEVICE.NUMBER),':',ITOA(BUTTON.INPUT.DEVICE.PORT),':',ITOA(BUTTON.INPUT.DEVICE.SYSTEM),
    										' | Actual Button Hold:',ITOA(BUTTON.INPUT.CHANNEL),' Get_Last Index:',ITOA(GET_LAST(nUSER_BTN_TEST))";
    		SEND_STRING 0,"'| Variable() -Dev:',ITOA(x),' Actual Dev:',
    										ITOA(BUTTON.INPUT.DEVICE.NUMBER),':',ITOA(BUTTON.INPUT.DEVICE.PORT),':',ITOA(BUTTON.INPUT.DEVICE.SYSTEM),
    										' | Actual Button Hold:',ITOA(BUTTON.INPUT.CHANNEL),' Get_Last Index:',ITOA(y)";
    		SEND_STRING 0,"'|       my() -Dev:',ITOA(myGetLastDev(BUTTON.INPUT.DEVICE,dvTPs)),' Actual Dev:',
    										ITOA(BUTTON.INPUT.DEVICE.NUMBER),':',ITOA(BUTTON.INPUT.DEVICE.PORT),':',ITOA(BUTTON.INPUT.DEVICE.SYSTEM),
    										' | Actual Button Hold:',ITOA(BUTTON.INPUT.CHANNEL),' myGetLast Index:',ITOA(myGetLast(BUTTON.INPUT.CHANNEL,nUSER_BTN_TEST))";
    
    		DO_PUSH_TIMED(dvTPs[RANDOM_NUMBER(5)+1],nUSER_BTN_TEST[RANDOM_NUMBER(15)+1],5);
    		
    	}
    	RELEASE:{
    		LOCAL_VAR INTEGER x,y;
    		x = GET_LAST(dvTPs);
    		y = GET_LAST(nUSER_BTN_TEST);
    		SEND_STRING 0,"'-=============================================================================-'";
    		SEND_STRING 0,"'|[RELEASE:]'";
    		SEND_STRING 0,"'| GET_LAST() -Dev:',ITOA(GET_LAST(dvTPs)),' Actual Dev:',
    										ITOA(BUTTON.INPUT.DEVICE.NUMBER),':',ITOA(BUTTON.INPUT.DEVICE.PORT),':',ITOA(BUTTON.INPUT.DEVICE.SYSTEM),
    										' | Actual Button Release:',ITOA(BUTTON.INPUT.CHANNEL),' Get_Last Index:',ITOA(GET_LAST(nUSER_BTN_TEST))";
    		SEND_STRING 0,"'| Variable() -Dev:',ITOA(x),' Actual Dev:',
    										ITOA(BUTTON.INPUT.DEVICE.NUMBER),':',ITOA(BUTTON.INPUT.DEVICE.PORT),':',ITOA(BUTTON.INPUT.DEVICE.SYSTEM),
    										' | Actual Button Release:',ITOA(BUTTON.INPUT.CHANNEL),' Get_Last Index:',ITOA(y)";
    		SEND_STRING 0,"'|       my() -Dev:',ITOA(myGetLastDev(BUTTON.INPUT.DEVICE,dvTPs)),' Actual Dev:',
    										ITOA(BUTTON.INPUT.DEVICE.NUMBER),':',ITOA(BUTTON.INPUT.DEVICE.PORT),':',ITOA(BUTTON.INPUT.DEVICE.SYSTEM),
    										' | Actual Button Release:',ITOA(BUTTON.INPUT.CHANNEL),' myGetLast Index:',ITOA(myGetLast(BUTTON.INPUT.CHANNEL,nUSER_BTN_TEST))";
    		SEND_STRING 0,"'/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/'";
    	}
    
    }
    

    and here are the results:
    Line      1 (17:54:29):: ###############################################################################
    Line      2 (17:54:29):: |[PUSH:]
    Line      3 (17:54:29):: | GET_LAST() -Dev:3 Actual Dev:10003:1:1 | Actual Button Push:5 Get_Last Index:5
    Line      4 (17:54:29):: | Variable() -Dev:3 Actual Dev:10003:1:1 | Actual Button Push:5 Get_Last Index:5
    Line      5 (17:54:29):: |       my() -Dev:3 Actual Dev:10003:1:1 | Actual Button Push:5 myGetLast Index:5
    Line      6 (17:54:31):: *******************************************************************************
    Line      7 (17:54:31):: |[HOLD:]
    Line      8 (17:54:31):: | GET_LAST() -Dev:3 Actual Dev:10003:1:1 | Actual Button Hold:5 Get_Last Index:5
    Line      9 (17:54:31):: | Variable() -Dev:3 Actual Dev:10003:1:1 | Actual Button Hold:5 Get_Last Index:5
    Line     10 (17:54:31):: |       my() -Dev:3 Actual Dev:10003:1:1 | Actual Button Hold:5 myGetLast Index:5
    Line     11 (17:54:31):: ###############################################################################
    Line     12 (17:54:31):: |[PUSH:]
    Line     13 (17:54:31):: | GET_LAST() -Dev:4 Actual Dev:10004:1:1 | Actual Button Push:6 Get_Last Index:6
    Line     14 (17:54:31):: | Variable() -Dev:4 Actual Dev:10004:1:1 | Actual Button Push:6 Get_Last Index:6
    Line     15 (17:54:31):: |       my() -Dev:4 Actual Dev:10004:1:1 | Actual Button Push:6 myGetLast Index:6
    Line     16 (17:54:32):: -=============================================================================-
    Line     17 (17:54:32):: |[RELEASE:]
    Line     18 (17:54:32):: | GET_LAST() -Dev:4 Actual Dev:10004:1:1 | Actual Button Release:6 Get_Last Index:6
    Line     19 (17:54:32):: | Variable() -Dev:4 Actual Dev:10004:1:1 | Actual Button Release:6 Get_Last Index:6
    Line     20 (17:54:32):: |       my() -Dev:4 Actual Dev:10004:1:1 | Actual Button Release:6 myGetLast Index:6
    Line     21 (17:54:32):: /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
    Line     22 (17:54:33):: *******************************************************************************
    Line     23 (17:54:33):: |[HOLD:]
    Line     24 (17:54:33):: | GET_LAST() -Dev:4 Actual Dev:10003:1:1 | Actual Button Hold:5 Get_Last Index:6
    Line     25 (17:54:33):: | Variable() -Dev:4 Actual Dev:10003:1:1 | Actual Button Hold:5 Get_Last Index:6
    Line     26 (17:54:33):: |       my() -Dev:3 Actual Dev:10003:1:1 | Actual Button Hold:5 myGetLast Index:5
    Line     27 (17:54:33):: ###############################################################################
    Line     28 (17:54:33):: |[PUSH:]
    Line     29 (17:54:33):: | GET_LAST() -Dev:4 Actual Dev:10004:1:1 | Actual Button Push:2 Get_Last Index:2
    Line     30 (17:54:33):: | Variable() -Dev:4 Actual Dev:10004:1:1 | Actual Button Push:2 Get_Last Index:2
    Line     31 (17:54:33):: |       my() -Dev:4 Actual Dev:10004:1:1 | Actual Button Push:2 myGetLast Index:2
    Line     32 (17:54:34):: -=============================================================================-
    Line     33 (17:54:34):: |[RELEASE:]
    Line     34 (17:54:34):: | GET_LAST() -Dev:4 Actual Dev:10004:1:1 | Actual Button Release:2 Get_Last Index:2
    Line     35 (17:54:34):: | Variable() -Dev:4 Actual Dev:10004:1:1 | Actual Button Release:2 Get_Last Index:2
    Line     36 (17:54:34):: |       my() -Dev:4 Actual Dev:10004:1:1 | Actual Button Release:2 myGetLast Index:2
    Line     37 (17:54:34):: /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
    Line     38 (17:54:35):: *******************************************************************************
    Line     39 (17:54:35):: |[HOLD:]
    Line     40 (17:54:35):: | GET_LAST() -Dev:4 Actual Dev:10003:1:1 | Actual Button Hold:5 Get_Last Index:2
    Line     41 (17:54:35):: | Variable() -Dev:4 Actual Dev:10003:1:1 | Actual Button Hold:5 Get_Last Index:2
    Line     42 (17:54:35):: |       my() -Dev:3 Actual Dev:10003:1:1 | Actual Button Hold:5 myGetLast Index:5
    Line     43 (17:54:37):: *******************************************************************************
    Line     44 (17:54:37):: |[HOLD:]
    Line     45 (17:54:37):: | GET_LAST() -Dev:4 Actual Dev:10003:1:1 | Actual Button Hold:5 Get_Last Index:2
    Line     46 (17:54:37):: | Variable() -Dev:4 Actual Dev:10003:1:1 | Actual Button Hold:5 Get_Last Index:2
    Line     47 (17:54:37):: |       my() -Dev:3 Actual Dev:10003:1:1 | Actual Button Hold:5 myGetLast Index:5
    Line     48 (17:54:37):: ###############################################################################
    Line     49 (17:54:37):: |[PUSH:]
    Line     50 (17:54:37):: | GET_LAST() -Dev:3 Actual Dev:10003:1:1 | Actual Button Push:14 Get_Last Index:14
    Line     51 (17:54:37):: | Variable() -Dev:3 Actual Dev:10003:1:1 | Actual Button Push:14 Get_Last Index:14
    Line     52 (17:54:37):: |       my() -Dev:3 Actual Dev:10003:1:1 | Actual Button Push:14 myGetLast Index:14
    Line     53 (17:54:38):: -=============================================================================-
    Line     54 (17:54:38):: |[RELEASE:]
    Line     55 (17:54:38):: | GET_LAST() -Dev:3 Actual Dev:10003:1:1 | Actual Button Release:14 Get_Last Index:14
    Line     56 (17:54:38):: | Variable() -Dev:3 Actual Dev:10003:1:1 | Actual Button Release:14 Get_Last Index:14
    Line     57 (17:54:38):: |       my() -Dev:3 Actual Dev:10003:1:1 | Actual Button Release:14 myGetLast Index:14
    Line     58 (17:54:38):: /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
    Line     59 (17:54:39):: *******************************************************************************
    Line     60 (17:54:39):: |[HOLD:]
    Line     61 (17:54:39):: | GET_LAST() -Dev:3 Actual Dev:10003:1:1 | Actual Button Hold:5 Get_Last Index:14
    Line     62 (17:54:39):: | Variable() -Dev:3 Actual Dev:10003:1:1 | Actual Button Hold:5 Get_Last Index:14
    Line     63 (17:54:39):: |       my() -Dev:3 Actual Dev:10003:1:1 | Actual Button Hold:5 myGetLast Index:5
    Line     64 (17:54:39):: ###############################################################################
    Line     65 (17:54:39):: |[PUSH:]
    Line     66 (17:54:39):: | GET_LAST() -Dev:4 Actual Dev:10004:1:1 | Actual Button Push:2 Get_Last Index:2
    Line     67 (17:54:39):: | Variable() -Dev:4 Actual Dev:10004:1:1 | Actual Button Push:2 Get_Last Index:2
    Line     68 (17:54:39):: |       my() -Dev:4 Actual Dev:10004:1:1 | Actual Button Push:2 myGetLast Index:2
    Line     69 (17:54:40):: -=============================================================================-
    Line     70 (17:54:40):: |[RELEASE:]
    Line     71 (17:54:40):: | GET_LAST() -Dev:4 Actual Dev:10004:1:1 | Actual Button Release:2 Get_Last Index:2
    Line     72 (17:54:40):: | Variable() -Dev:4 Actual Dev:10004:1:1 | Actual Button Release:2 Get_Last Index:2
    Line     73 (17:54:40):: |       my() -Dev:4 Actual Dev:10004:1:1 | Actual Button Release:2 myGetLast Index:2
    Line     74 (17:54:40):: /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
    Line     75 (17:54:41):: -=============================================================================-
    Line     76 (17:54:41):: |[RELEASE:]
    Line     77 (17:54:41):: | GET_LAST() -Dev:3 Actual Dev:10003:1:1 | Actual Button Release:5 Get_Last Index:5
    Line     78 (17:54:41):: | Variable() -Dev:3 Actual Dev:10003:1:1 | Actual Button Release:5 Get_Last Index:5
    Line     79 (17:54:41):: |       my() -Dev:3 Actual Dev:10003:1:1 | Actual Button Release:5 myGetLast Index:5
    Line     80 (17:54:41):: /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
    

    As you can see, any use of the GET_LAST() function in a hold is a potential problem. I did this test because I am considering switching a bunch of my modules away from GET_LAST only because there are a few places where a HOLD event is used and I would rather be uniform in my approach. By using the 2 new functions, I can fairly quickly and easily replace my existing GET_LAST code.

    Does anyone see any flaw in my testing or in my functions? I'd really hate to make the switch only to find some weird new problem I introduce :)

    Yes, I could store BIC values in an array, but that sounds like more work than just using the replacement functions. It also seems like I might need to rework some of the code to deal with BIC data.

    Jeff
  • viningvining Posts: 4,368
    First, I wish we could declare local variables at the begining of BUTTON_EVENT that could be with in the scope of the entire BUTTON_EVENT and not just the individual PUSH, HOLD & RELEASE.

    Like this!
    BUTTON_EVENT [dvTP_Arry,nAP_BtnArry] 
    
         {
         LOCAL_VAR INTEGER nLastInPut ;
         
         PUSH:
    	  {
    	  //push code
    	  }
         HOLD[2,REPEAT]:
    	  {
    	  //hold code
    	  }
         RELEASE:
    	  {
    	  //release code
    	  }
         }
    
    Not being able to do this always seemed to bug me cuz now I need a global var where if this were possible I wouldn't.
    DEFINE_VARIABLE
    
    VOLATILE INTEGER nBTN ;
    
    BUTTON_EVENT [dvTP_Arry,nAP_BtnArry] 
    
         {
         PUSH:
    	  {
    	  STACK_VAR CHAR cDevice[11] ;
    	  LOCAL_VAR INTEGER nLastInPut ;
      	  
    	  nBTN = GET_LAST(nAP_BtnArry)
    	  dvCurPushTP = BUTTON.INPUT.DEVICE ;
    	  cDevice = fnDEV_TO_STRING(dvCurPushTP) ;
    	  fnDebug("'Device:',cDevice,'-CHANNEL ',itoa(nAP_BtnArry[nBTN]),' Line-<',ITOA(__LINE__),'>'") ;
    	  if(nHold_In_Progress)
    	       {
    	       fnDoMSGDisplay(dvCurPushTP,'Please Wait ** System Busy',MSG_TYPE_WARNING,AP_UNIT_0) ;
    	       nHold_MSG_Sent = 1 ;
    	       }
    	  else
    
      }  
         HOLD[2,REPEAT]:
    	  {
    	  nHold_In_Progress = 1 ;
    	  
    	  SELECT
    	       {
    	       ACTIVE (nBTN >= BTN_VOL_UP && nBTN <= BTN_VOL_RMP_DWN):
    
    RELEASE:
    	  {
    	  nHold_In_Progress = 0 ;
    
    

    I prefer the blocking method. Do the GET_LAST in the PUSH and set a blocking var in the hold that prevents the PUSH code blocking from running and changing values while the HOLD is in progress for the duration of the HOLD.

    Yes, I put in a "Please Wait" pop up message just in case and I don't care if any one dis-agrees with this approach (Paul) but my thinking is that it will never get called any way.

    Just for clarification, does GET_LAST hold the last value for each event table or does GET_LAST return the last value across the entire system? In other words if I use a GET_LAST in a hold or wait for BUTTON_EVENT [dvTP_Arry,nAP_BtnArry] will it only return the last channel push in that EVENT_TABLE or will it use the last channel pushed any where and see what index that channel number may be in nAP_BtnArry.
  • Spire_JeffSpire_Jeff Posts: 1,917
    vining wrote: »
    DEFINE_VARIABLE
    
    VOLATILE INTEGER nBTN ;
    
    BUTTON_EVENT [dvTP_Arry,nAP_BtnArry] 
    
         {
         PUSH:
    	  {
    	  STACK_VAR CHAR cDevice[11] ;
    	  LOCAL_VAR INTEGER nLastInPut ;
      	  
    	  nBTN = GET_LAST(nAP_BtnArry)
    	  dvCurPushTP = BUTTON.INPUT.DEVICE ;
    	  cDevice = fnDEV_TO_STRING(dvCurPushTP) ;
    	  fnDebug("'Device:',cDevice,'-CHANNEL ',itoa(nAP_BtnArry[nBTN]),' Line-<',ITOA(__LINE__),'>'") ;
    	  if(nHold_In_Progress)
    	       {
    	       fnDoMSGDisplay(dvCurPushTP,'Please Wait ** System Busy',MSG_TYPE_WARNING,AP_UNIT_0) ;
    	       nHold_MSG_Sent = 1 ;
    	       }
    	  else
    
      }  
         HOLD[2,REPEAT]:
    	  {
    	  nHold_In_Progress = 1 ;
    	  
    	  SELECT
    	       {
    	       ACTIVE (nBTN >= BTN_VOL_UP && nBTN <= BTN_VOL_RMP_DWN):
    
    RELEASE:
    	  {
    	  nHold_In_Progress = 0 ;
    
    

    I prefer the blocking method. Do the GET_LAST in the PUSH and set a blocking var in the hold that prevents the PUSH code blocking from running and changing values while the HOLD is in progress for the duration of the HOLD.

    ....

    Just for clarification, does GET_LAST hold the last value for each event table or does GET_LAST return the last value across the entire system? In other words if I use a GET_LAST in a hold or wait for BUTTON_EVENT [dvTP_Arry,nAP_BtnArry] will it only return the last channel push in that EVENT_TABLE or will it use the last channel pushed any where and see what index that channel number may be in nAP_BtnArry.

    I believe the way you have the Push: Event defined here, there is a potential to run into the problem I described. The reason is because you are executing the GET_LAST function every time the button is pushed and this portion of the code is not conditional based upon the lock out. If you moved the GET_LAST inside the ELSE portion of the IF(nHold_In_Progress) ... ELSE statement, this should work properly.

    As for the GET_LAST applying to the event or the system, I will see if I can test that out tomorrow.

    Jeff
  • viningvining Posts: 4,368
    Spire_Jeff wrote:
    I believe the way you have the Push: Event defined here, there is a potential to run into the problem I described.
    You are so very right! Sometimes we see but are still blind.
  • Spire_JeffSpire_Jeff Posts: 1,917
    vining wrote: »
    Just for clarification, does GET_LAST hold the last value for each event table or does GET_LAST return the last value across the entire system? In other words if I use a GET_LAST in a hold or wait for BUTTON_EVENT [dvTP_Arry,nAP_BtnArry] will it only return the last channel push in that EVENT_TABLE or will it use the last channel pushed any where and see what index that channel number may be in nAP_BtnArry.

    Now that I've had some sleep, I think I understand what you are asking. GET_LAST monitors the each array separately (I think). So, if you have the following:
    INTEGER nUSER_BTN_TEST1[] = {21,22,23,24,25,26,27,28,29,30,31,32,33,34,35}
    INTEGER nUSER_BTN_TEST2[] = {41,42,43,44,45,46,47,48,49,50,51,52,53,54,55}
    INTEGER nUSER_BTN_TEST3[] = {21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,
    								36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,
    								51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,
    								66,67,68,69,70,71,72,73,74,75,76,77,78,79,80
    														}
    .
    .
    .
    .
    BUTTON_EVENT[dvTPs,nUSER_BTN_TEST3]{
    	PUSH:{
    		SEND_STRING 0,"'Button ',ITOA(BUTTON.INPUT.CHANNEL),' was pushed!  ********************'";
    	}
    	RELEASE:{
    		SEND_STRING 0,"'Button ',ITOA(BUTTON.INPUT.CHANNEL),' was released!  ******************'";
    	}
    }
    
    BUTTON_EVENT[dvTPs,43]{
    	PUSH:{
    		SEND_STRING 0,"'Button 43: GET_LAST(Array1) = ',ITOA(GET_LAST(nUSER_BTN_TEST1))";
    		SEND_STRING 0,"'Button 43: GET_LAST(Array2) = ',ITOA(GET_LAST(nUSER_BTN_TEST2))";
    	}
    }
    BUTTON_EVENT[dvTPs,32]{
    	PUSH:{
    		SEND_STRING 0,"'Button 32(Instance 1): GET_LAST(Array1) = ',ITOA(GET_LAST(nUSER_BTN_TEST1))";
    		SEND_STRING 0,"'Button 32(Instance 1): GET_LAST(Array2) = ',ITOA(GET_LAST(nUSER_BTN_TEST2))";
    	}
    }
    
    BUTTON_EVENT[dvTPs,nUSER_BTN_TEST1]{
    	PUSH:
    		SEND_STRING 0,"'nUSER_BTN_TEST1: GET_LAST() = ',ITOA(GET_LAST(nUSER_BTN_TEST1))";
    }
    BUTTON_EVENT[dvTPs,nUSER_BTN_TEST2]{
    	PUSH:
    		SEND_STRING 0,"'nUSER_BTN_TEST2: GET_LAST() = ',ITOA(GET_LAST(nUSER_BTN_TEST2))";
    }
    BUTTON_EVENT[dvTPs,32]{
    	PUSH:{
    		SEND_STRING 0,"'Button 32(Instance 2): GET_LAST(Array1) = ',ITOA(GET_LAST(nUSER_BTN_TEST1))";
    		SEND_STRING 0,"'Button 32(Instance 2): GET_LAST(Array2) = ',ITOA(GET_LAST(nUSER_BTN_TEST2))";
    	}
    }
    BUTTON_EVENT[dvTPs,44]{
    	PUSH:{
    		SEND_STRING 0,"'Button 44: GET_LAST(Array1) = ',ITOA(GET_LAST(nUSER_BTN_TEST1))";
    		SEND_STRING 0,"'Button 44: GET_LAST(Array2) = ',ITOA(GET_LAST(nUSER_BTN_TEST2))";
    	}
    }
    BUTTON_EVENT[dvTPs,39]{
    	PUSH:{
    		SEND_STRING 0,"'Button 39: GET_LAST(Array1) = ',ITOA(GET_LAST(nUSER_BTN_TEST1))";
    		SEND_STRING 0,"'Button 39: GET_LAST(Array2) = ',ITOA(GET_LAST(nUSER_BTN_TEST2))";
    	}
    }
    
    

    Here is the output to demonstrate the GET_LAST Functionality:
    Line      1 (11:00:34):: Button 21 was pushed!  ********************
    Line      2 (11:00:34):: nUSER_BTN_TEST1: GET_LAST() = 1
    Line      3 (11:00:34):: Button 21 was released!  ******************
    Line      4 (11:00:41):: Button 25 was pushed!  ********************
    Line      5 (11:00:41):: nUSER_BTN_TEST1: GET_LAST() = 5
    Line      6 (11:00:41):: Button 25 was released!  ******************
    Line      7 (11:00:47):: Button 32 was pushed!  ********************
    Line      8 (11:00:47):: Button 32(Instance 1): GET_LAST(Array1) = 12
    Line      9 (11:00:47):: Button 32(Instance 1): GET_LAST(Array2) = 0
    Line     10 (11:00:47):: nUSER_BTN_TEST1: GET_LAST() = 12
    Line     11 (11:00:47):: Button 32(Instance 2): GET_LAST(Array1) = 12
    Line     12 (11:00:47):: Button 32(Instance 2): GET_LAST(Array2) = 0
    Line     13 (11:00:47):: Button 32 was released!  ******************
    Line     14 (11:00:57):: Button 41 was pushed!  ********************
    Line     15 (11:00:57):: nUSER_BTN_TEST2: GET_LAST() = 1
    Line     16 (11:00:57):: Button 41 was released!  ******************
    Line     17 (11:01:03):: Button 44 was pushed!  ********************
    Line     18 (11:01:03):: nUSER_BTN_TEST2: GET_LAST() = 4
    Line     19 (11:01:03):: Button 44: GET_LAST(Array1) = 12
    Line     20 (11:01:03):: Button 44: GET_LAST(Array2) = 4
    Line     21 (11:01:03):: Button 44 was released!  ******************
    Line     22 (11:01:11):: Button 32 was pushed!  ********************
    Line     23 (11:01:11):: Button 32(Instance 1): GET_LAST(Array1) = 12
    Line     24 (11:01:11):: Button 32(Instance 1): GET_LAST(Array2) = 4
    Line     25 (11:01:11):: nUSER_BTN_TEST1: GET_LAST() = 12
    Line     26 (11:01:11):: Button 32(Instance 2): GET_LAST(Array1) = 12
    Line     27 (11:01:11):: Button 32(Instance 2): GET_LAST(Array2) = 4
    Line     28 (11:01:11):: Button 32 was released!  ******************
    Line     29 (11:01:25):: Button 31 was pushed!  ********************
    Line     30 (11:01:25):: nUSER_BTN_TEST1: GET_LAST() = 11
    Line     31 (11:01:25):: Button 31 was released!  ******************
    Line     32 (11:01:28):: Button 32 was pushed!  ********************
    Line     33 (11:01:28):: Button 32(Instance 1): GET_LAST(Array1) = 12
    Line     34 (11:01:28):: Button 32(Instance 1): GET_LAST(Array2) = 4
    Line     35 (11:01:28):: nUSER_BTN_TEST1: GET_LAST() = 12
    Line     36 (11:01:28):: Button 32(Instance 2): GET_LAST(Array1) = 12
    Line     37 (11:01:28):: Button 32(Instance 2): GET_LAST(Array2) = 4
    Line     38 (11:01:29):: Button 32 was released!  ******************
    Line     39 (11:03:16):: Button 39 was pushed!  ********************
    Line     40 (11:03:16):: Button 39: GET_LAST(Array1) = 12
    Line     41 (11:03:16):: Button 39: GET_LAST(Array2) = 4
    Line     42 (11:03:16):: Button 39 was released!  ******************
    Line     43 (11:03:21):: Button 38 was pushed!  ********************
    Line     44 (11:03:21):: Button 38 was released!  ******************
    Line     45 (11:03:28):: Button 39 was pushed!  ********************
    Line     46 (11:03:28):: Button 39: GET_LAST(Array1) = 12
    Line     47 (11:03:28):: Button 39: GET_LAST(Array2) = 4
    Line     48 (11:03:28):: Button 39 was released!  ******************
    

    One thing that I found interesting is that GET_LAST seems to update the value before it goes through the events. If you look at the events for button 32, the first event is not declared using the array, it is just a constant. Given this fact, I thought there was a chance that GET_LAST might not update until it hit an event declared with the array. It seems that I was wrong :)

    Hope this helps someone else, but it has definitely helped my understanding of GET_LAST() .... more importantly, why I need to stop using it in some of my modules :)

    Jeff
Sign In or Register to comment.