Get_Last alternatives
jjames
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. 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.
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. 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.
0
Comments
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...
Jeff
P.S.
I use Get_Last a lot because I need an indexed value of the push. It just makes the math easier
For example let's say you have a button array like this
nButtons={1,2,3,5,6}
example:
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.
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.
You could also write one that works for devices:
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
Did I miss something? What's wrong with Get_Last?
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.
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.
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:
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.
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.
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.
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.
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.
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
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.
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.
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.
First, I had to modify the myGetLastDev function slightly to account for devices declared with a system of 0. Here are the new functions:
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:
and here are the results:
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
Like this! 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.
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.
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
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:
Here is the output to demonstrate the GET_LAST Functionality:
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