Since the previous code I posted had logical flaws in respect to the whole GET_LAST thing especially when dealing with HOLDs I figured I'd re-write it and correct the mistake and then notice other mistakes besides the obvioius.
It appeared to me that putting blocking VAR in the push even if I did it right wouldn't work because the release would have changed the values as well if some one else pushed/released a TP's button that ran through this code block while a HOLD was in progress on another TP. So I had to modify the way that worked as well.
This revision doesn't actually block further pushes or releases any more either but simple holds the HOLD values for use during a hold and then compares release values to the hold values to determine if the correct (BTN being held) button was released. So if my thinking is correct other TPs can still use this code while a hold is in progress and there should be no negative outcome.
The only thing I'm not sure of is what happens when another TP using this same device/code HOLDs a button at the same time. My thinking is that nothing will happen, no second hold taking over or changing values since the hold is affectively a wait. My thinking that since a "HOLD" wait is pending another attemp to "HOLD" wait will simply be disregarded.
DEFINE_VARIABLE //VAV VARS
VOLATILE INTEGER nHOLD_BTN = 0 ;
VOLATILE INTEGER nHOLD_TP_INDEX = 0 ;
VOLATILE INTEGER nHold_In_Progress = 0 ;
BUTTON_EVENT[dvTPArry,nBtnArry] //Buttons pushed
{
PUSH:
{
STACK_VAR INTEGER nPUSH_BTN ;
STACK_VAR INTEGER nPUSH_TP_INDEX ;
if(!nHold_In_Progress)
{
nHOLD_BTN = GET_LAST(nBtnArry) ; //Get index of last BTN whose button was Pushed. For Hold & Release code block.
nHOLD_TP_INDEX = GET_LAST(dvTPArry) ; //Get index of last TP whose button was Pushed. For Hold & Release code block.
}
nPUSH_BTN = GET_LAST(nBtnArry) ; //Get index of last BTN whose button was Pushed. For this code block
nPUSH_TP_INDEX = GET_LAST(dvTPArry) ; //Get index of last TP whose button was Pushed. For this code block
SWITCH(nPUSH_BTN)
{
CASE 1:
{
//
}
CASE 2:
{
//
}
}
}
HOLD[6,REPEAT]:
{
nHold_In_Progress = 1 ;
SWITCH(nHOLD_BTN)
{
CASE 5:
{
//
}
CASE 6:
{
//
}
}
}
RELEASE:
{
STACK_VAR INTEGER nTPArryIndex ;
STACK_VAR INTEGER nRELEASE_BTN ;
nTPArryIndex = GET_LAST(dvTPArry) ; //Get index of last TP whose button was released
nRELEASE_BTN = GET_LAST(nBtnArry) ; //Get index of last button released on panel
if((nRELEASE_BTN == nHOLD_BTN) && (nTPArryIndex == nHOLD_TP_INDEX))//don't waist time evaluating to DPS.
{
nHold_In_Progress = 0 ;
}
SWITCH(nRELEASE_BTN)
{
CASE 5:
{
//
}
CASE 6:
{
//
}
}
}
}
Fortunately the right thing happens when two TPs are holding an event for the same IR device. The hold for the first stops and the hold for the second device takes over. This seems like reasonable behavior to me so I leave it alone.
Paul
Fortunately the right thing happens when two TPs are holding an event for the same IR device. The hold for the first stops and the hold for the second device takes over. This seems like reasonable behavior to me so I leave it alone.
Paul
So it's reasonable to have the 1st user get bumped by another user. The point of this thread was trying to avoid that. If any thing the code should be written so the 1st user takes presedence and if nothing else locks out the ability of another user from screwing up the 1st users inputs until he/she are finished.
The question is does the system treat the hold like a system named wait or in other words any wait in the system that isn't explicitly named by us. Then I would think in the code I just posted that the second hold would be ignored since the wait is already pending. Of course If I had time I could test it but that not going to happen any time soon.
a_riot42 wrote:
So it's reasonable to have the 1st user get bumped by another user. The point of this thread was trying to avoid that. If any thing the code should be written so the 1st user takes presedence and if nothing else locks out the ability of another user from screwing up the 1st users inputs until he/she are finished.
I don't agree, but obviously its a judgement call. A user can't expect a device to respond to two holds at the same time from two different UIs so the question is what should happen in that event.
You can do as you do, and block a user from being able to trigger a hold, and popping up your "Please wait...System busy" popup, annoying the user further and adding to their confusion as to why the device isn't responding correctly. Or you can just not do anything, and let the system sort it out for you, in which case if a user is holding a button and it mysteriously stops holding its fairly obvious someone else has taken control from you and you will have to hit the button again if you want to regain control.
This scenario means that whoever hit a button on a UI most recently, has control, which is more consistent to me than whoever hit a button most recently has control unless someone is holding a button and then you are blocked until all users release that button, and you have cleared your "Please wait...System busy" popup, by which time someone has hit hold again so you get the popup again, and so on and so on, until you are so tired and confused you turn off the TV and go to bed.
My way means noone is ever denied control when they ask for it, but it may impinge on another user should they be using a hold when you want to as well. C'est la vie n'est-pa?
Paul
Well the likely hood of two users trying to issue holds simultaneously on the same device/code block is rare enough for me not to worry about it but the idea of the 1st user getting bumped by the 2nd user who then gets bumped by the 1st user trying to continue his task who then get bumped again by the 2nd user so on and so forth as they both try to ramp their volume in their respective areas is a real clever way of handling things. My method of "Please Wait" or your method of "ignorance is bliss" so they will just think the system is screwed up, your right, it's a judgement call.
Actually the method I most recently posted doesn't use a "Please Wait" and although not tested it should allow both users to do pushes even if one person is holding. My only thought was if the second person tried a hold while the first person was holding, the second hold wouldn't execute the way my code is written but that depends on how the system evaluates the hold, is it like a wait or not? I think that's prefferable to the dueling hold method since we're only talking about a second or two of waiting. Plus individual button pushes would still work and most folks aren't even aware that they can actually do holds anyway.
I don't agree, but obviously its a judgement call. A user can't expect a device to respond to two holds at the same time from two different UIs so the question is what should happen in that event.
So when two users try to change their respective audio zones off of an Autopatch or anything other RS-232 device, someone should get locked out? I beg to differ. Things like that are EASILY avoidable with timelines. Fire a timeline off for each zone that's trying to adjusted.
Now, two users trying to control the same IR device, that's a different story, but then again - how often is someone going to try to control the same satellite box, or cable box, or anything else that's IR? And you know, if it's explained to the users well enough, there will never be a problem. The users need to know the limitations. Period.
Things like that are EASILY avoidable with timelines. Fire a timeline off for each zone that's trying to adjusted.
That would actually solve the problem completely. Do you create a time line ID for each zone or create just enough to cover the max amount of users that could ever possibly what to change volume at the same time plus 1 for good measure and pick the 1st available !ACTIVE?
That would actually solve the problem completely. Do you create a time line ID for each zone or create just enough to cover the max amount of users that could ever possibly what to change volume at the same time plus 1 for good measure and pick the 1st available !ACTIVE?
I use the number of outputs on whatever audio switcher we're using (usually an 18x18 Autopatch.) So there are always at least 18 timelines, even if at the moment we're using 10 of those outputs (allows for expandability.) Now of course, no two people can control the same zone at the same time (i.e. one wants to go up, the other wants to go down), but again - that's just an obvious limitation of the system the user needs to understand.
Here's a code snippet:
BUTTON_EVENT[dv_TP,nVOLUME_BTNS]
{
PUSH:
{
STACK_VAR INTEGER nPNL
STACK_VAR INTEGER nAV_Zone
nPNL = GET_LAST(dv_TP)
// ASSIGN CURRENT AV ZONE
nAV_Zone = nAV_ZONE_MAP[nPNL][1]
// If the zone is on, and it's not already being ramped
IF (nAV_ZONE_SOURCE[nAV_Zone] AND (!nVOL_RAMP_STATE[nAV_Zone]))
{
// Assign direction (1-up, 2-down, 3-mute)
nVOL_RAMP_STATE[nAV_Zone] = GET_LAST(nVOLUME_BTNS)
// If it's not the mute button
IF (BUTTON.INPUT.CHANNEL <> nVOLUME_BTNS[3])
{
ON[BUTTON.INPUT]
// If it's mute, go ahead and unmute it here....
// Fire off your time line for that zone
TIMELINE_CREATE(nAV_Zone+10,nVOL_RAMP_DELAY,1,TIMELINE_RELATIVE,TIMELINE_ONCE)
}
// Mute button
ELSE
{
nZONE_VOL_MUTE[nAV_Zone] = !nZONE_VOL_MUTE[nAV_Zone] // TOGGLE MUTE
// Send string or do function to mute
}
}
}
RELEASE:
{
STACK_VAR INTEGER nPNL
STACK_VAR INTEGER nAV_Zone
nPNL = GET_LAST(dv_TP)
// ASSIGN CURRENT AV ZONE
nAV_Zone = nPNL_AV[nPNL]
// Turn off the "ramp" state
nVOL_RAMP_STATE[nAV_Zone] = 0
// Is the zone on?
IF (nAV_ZONE_SOURCE[nAV_Zone])
{
// If it's not the mute button, turn off feedback
IF (BUTTON.INPUT.CHANNEL <> nVOLUME_BTNS[3])
OFF[BUTTON.INPUT]
// Kill the timeline
IF (TIMELINE_ACTIVE(nAV_Zone+10))
TIMELINE_KILL(nAV_Zone+10)
}
}
}
How would using a timeline help if more than one person is holding a button that affects a single IR device? The problem is the IR device not being able to handle simultaneous IR commands that is the problem, not the control system. Since it can happen in multizone projects using global sources what happens in that case using your timeline approach?
In your volume code, I am assuming you are not using the AP Duet module? I guess I am confused why you are using a timeline to control volume on a RS232 switch? I guess I haven't encountered the problem you are trying to solve.
Paul
How would using a timeline help if more than one person is holding a button that affects a single IR device? The problem is the IR device not being able to handle simultaneous IR commands that is the problem, not the control system. Since it can happen in multizone projects using global sources what happens in that case using your timeline approach?
Instead of jumping the gun and shooting your mouth off like usual, allow me to quote myself:
Now, two users trying to control the same IR device, that's a different story, but then again - how often is someone going to try to control the same satellite box, or cable box, or anything else that's IR? And you know, if it's explained to the users well enough, there will never be a problem. The users need to know the limitations. Period.
Translation:
I know you can't control an IR device with more than two codes at the same time, which is a limitation of the system and needs to be explained to the client. Period.
In your volume code, I am assuming you are not using the AP Duet module?
No - I don't use modules with devices I use time and time again. I prefer to use my own code, as they're usually way too bloated and rarely achieve what I'm trying to do.
Translation:
I know you can't control an IR device with more than two codes at the same time, which is a limitation of the system and needs to be explained to the client. Period.
Yes, but that wasn't my question. There are apparently at least two different ways of dealing with this, one is the way Vinning recommends which is to block other users, and the way I do it which is to always give control to the last user in a hold and not block. You didn't answer the question of what your method does in that instance.
How else do you plan on doing it? Instead of criticizing everything, why not pony up the "perfect" code you use?
I use the AMX AP module which seems to deal with this quite well so it isn't a problem I have come across. Perhaps your module is dealing with that situation differently and so you encounter the issue more regularly.
Paul
I use the AMX AP module which seems to deal with this quite well so it isn't a problem I have come across. Perhaps your module is dealing with that situation differently and so you encounter the issue more regularly.
I don't understand . . . because I don't have an issue I'm encountering, what I posted works fine. Though of course it is watered down, but the idea remains.
Yes, but that wasn't my question. There are apparently at least two different ways of dealing with this, one is the way Vinning recommends which is to block other users, and the way I do it which is to always give control to the last user in a hold and not block. You didn't answer the question of what your method does in that instance.
My posted method does nothing with IR.
Maybe I didn't answer the question because I *very rarely* use HOLD events, and never to control a device.
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
If you assign the result of get_last to a variable then there should be no problem, like Dave mentions. Since the result is in a variable, it doesn't matter if another panel uses the same hold code since it will be operating on a different variable. From the testing I have done, get_last will return the last touch panel button pressed system-wide.
I don't understand why you would write functions that duplicate built-in functions. get_last probably has access to a pointer that you don't have access to, and hence you have to search arrays in linear time.
There is no point in calling get_last in a hold event because its return value could be a different panel/channel/etc than the one that caused the push you are holding on. That is the point of storing it in a variable.
I don't understand why you would write functions that duplicate built-in functions. get_last probably has access to a pointer that you don't have access to, and hence you have to search arrays in linear time.
There is no point in calling get_last in a hold event because its return value could be a different panel/channel/etc than the one that caused the push you are holding on. That is the point of storing it in a variable.
All of the tests I ran with the built-in GET_LAST indicate that it is doing the same thing my function does, only it seems to be overloaded in that you can pass it an array of integers or an array of devices. For some reason, it also does not function properly on a hold. The functions I wrote do work properly in a hold event.
Now that I think about it, GET_LAST does work a little differently than my function. It is obviously tracking all of these events somewhere as you can call GET_LAST from anywhere and it will return the last value for the array you pass it. In order for my functions to work the same way, you would need to create tracking variables for every array you want to track, then update the tracking variables when ever an event occurs that involves a member of every array being tracked. This would actually add a lot of overhead and it would in fact cause the same problems that currently exist in GET_LAST. This raises a question: Does the processor ALWAYS track this information, or does it build these tracking variables only when a GET_LAST is used in code?
The reason I initially wrote the modules was to explore and enhance my understanding of the NetLinx processor and its functionality. After writing the functions, and seeing that they work, I have decided to use them because they let me easily update some old code that was written with GET_LAST. This is code that has been working fine, but the possibility did exist in which it would not function properly. By using a get_last that functions properly, I don't have to revisit or rewrite the rest of the code. This means less chance of screwing up functional code because I already tested the new functions and I haven't changed any of the other code.
In the end, I just developed a different way to skin the cat. It seems to me that your approach to deal with the flaws in GET_LAST is by writing additional code that is written to overcome the flaws. My approach is to simply fix the flaws in GET_LAST. Which way is correct? I would say both. A lot depends on what you are trying to accomplish. It sounds like your approach does add some other functionality, but in the situation I was faced with, I didn't need more, I just needed it to function the same in all cases. I consider my new functions as new tools in my tool box, I just need to know when to use them.
I'd prefer an Eminem attack... they tend rhyme and are done to a beat :P
I agree; if conflict is going to ensue, it might as well happen to a funky beat - be it Westside Story with some tap dancing and finger snapping, rapping until someone passes out or their mama has been thoroughly trash talked, or break dancing with serious attitude. Heck, given the present circumstances, I'd even settle for dueling programmers typing out mad code to a stellar rhythm.
LOL . . . c'mon . . . it was a completely harmless remark; it wasn't meant to be a put down. My apologies if it was taken that way though.
Anyway, back on subject . . . I have a question for the users of B.I.C., when writing an event, do you use the actual button number in the definition of the button event, or do you define a constant and use that instead?
When I use BIC I always assign a constant. I like having all of my button numbers assigned to either constants or arrays at the top of the program. If anything needs to change you don't have to go searching throughout the entire program.
In the end, I just developed a different way to skin the cat. It seems to me that your approach to deal with the flaws in GET_LAST is by writing additional code that is written to overcome the flaws. My approach is to simply fix the flaws in GET_LAST. Which way is correct? I would say both. A lot depends on what you are trying to accomplish. It sounds like your approach does add some other functionality, but in the situation I was faced with, I didn't need more, I just needed it to function the same in all cases. I consider my new functions as new tools in my tool box, I just need to know when to use them.
Jeff
I don't know if I would characterize it the way you are. I don't think there are any flaws in get_last per se. It does what it is supposed to do. The problem is the way a hold is implemented, in that the system doesn't know when a hold is actually occurring, it just assumes a hold is taking place when a push with no release happens. get_last cannot return the correct value in a hold since no hardware event occurs for a hold. Since a hold can go on for some time while other touch panels are being used, the value that get_last returns will change while you are processing the hold. The way around this is to save the result from get_last in the push and use it in the hold. That way it won't matter if three people are all holding the same button on three different UIs because the hold will process a different variable for each. You don't really need to write new functions, but of course you can if you want to. Rewriting system functions can have unintended consequences so you might find other bugs.
Paul
That way it won't matter if three people are all holding the same button on three different UIs because the hold will process a different variable for each.
Ya know it never occurred to me to make a "nTPs_ON_HOLD[nNum_TPs]" INTEGER array based on the number of TPs and then using my PUSH get_last TPArry index to track a hold for each TP. My brain was stuck on single HOLD var for all TPs. This should work equally as nice as TIME_LINES w/o the extra code.
Of course the likely hood of any of this really happening on any of my system is so rare it's not worth fussing about but having the knowledge should I choose to use it was worth the trip.
Of course the likely hood of any of this really happening on any of my system is so rare it's not worth fussing about but having the knowledge should I choose to use it was worth the trip.
I'd think you'd WANT to know when 5 kids were holding the same button, so that your control system could summon Captain Planet...
a_riot42 wrote:
Of course the likely hood of any of this really happening on any of my system is so rare it's not worth fussing about but having the knowledge should I choose to use it was worth the trip.
Lol...You sound like my boss. I always have the argument with him that rarity of an event shouldn't determine whether it works or not.
Paul
Does someone feel like testing get_last to see what happens if you have the same TP defined in two different arrays?
If you have two button events that have two different TP arrays, but there is an identical TP defined in each one, will get_last return different values for each button event?
define_device
dvTP1 = 10001:1:1
dvTP2 = 10002:1:1
dvTP3 = 10003:1:1
dvTPArray1[2] = {dvTP1, dvTP2}
dvTPArray2[2] = {dvTP2, dvTP3}
button_event{dvTPArray1, 10]
{
stack_var integer result
result = get_last(dvTPArray1)
}
button_event{dvTPArray2, 10]
{
stack_var integer result
result = get_last(dvTPArray2)
}
If get_last is implemented correctly, it should return two different values in each button event when button 10 is pressed on dvTP2.
Paul
DEFINE_DEVICE
dvTP_LGR = 10001:01:00 // MVP-8400i v2.83.9, IP - 192.168.1.81
dvTP_KIT = 10002:01:00 // MVP-8400i v2.83.9, IP - 192.168.1.82
dvTP_MBA = 10003:01:00 // NXD-CV7 v-.--.-, IP - 192.168.1.83
DEFINE_CONSTANT
DEV dv_TP_TEST1[]=
{
dvTP_LGR
,dvTP_KIT
}
DEV dv_TP_TEST2[]=
{
dvTP_KIT
,dvTP_MBA
}
DEFINE_EVENT
BUTTON_EVENT[dv_TP_TEST1,9993]
{
PUSH:
{
LOCAL_VAR INTEGER nRESULT1;
nRESULT1 = GET_LAST(dv_TP_TEST1);
SEND_STRING 0,"'Index ',ITOA(nRESULT1),' was pressed from Array 1'"
}
}
BUTTON_EVENT[dv_TP_TEST2,9993]
{
PUSH:
{
LOCAL_VAR INTEGER nRESULT2;
nRESULT2 = GET_LAST(dv_TP_TEST2);
SEND_STRING 0,"'Index ',ITOA(nRESULT2),' was pressed from Array 2'"
}
}
Results:
Line 9 (17:26:51.718):: Index 2 was pressed from Array 1
Line 10 (17:26:51.718):: Index 1 was pressed from Array 2
Multiple events are fired if the same button number and device code are defined, hence why sometimes you may get a double pulse or something with IR if one forgets to remove a specific statement from their code (an error I've made plenty of times when I first started coding.)
Does someone feel like testing get_last to see what happens if you have the same TP defined in two different arrays?
If you have two button events that have two different TP arrays, but there is an identical TP defined in each one, will get_last return different values for each button event?
If get_last is implemented correctly, it should return two different values in each button event when button 10 is pressed on dvTP2.
Paul
Push and Release function the way you describe. Hold is still subjected to the same limitations.
Here is the code I used:
DEFINE_VARIABLE
DEV dvTPs[] ={dvTEST1,dvTEST2,dvTEST3,dvTEST4,dvTEST5}
DEV dvTPs2[] ={dvTEST5,dvTEST4,dvTEST3,dvTEST2,dvTEST1}
DEFINE_EVENT
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_TEST1]{
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_TEST1[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,"'/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/'";
}
}
BUTTON_EVENT[dvTPs2,nUSER_BTN_TEST1]{
PUSH:{
LOCAL_VAR INTEGER x,y;
x = GET_LAST(dvTPs2);
y = GET_LAST(nUSER_BTN_TEST);
SEND_STRING 0,"'###############################################################################'";
SEND_STRING 0,"'|[PUSH:]'";
SEND_STRING 0,"'| GET_LAST() -Dev:',ITOA(GET_LAST(dvTPs2)),' 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,dvTPs2)),' 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(dvTPs2);
y = GET_LAST(nUSER_BTN_TEST);
SEND_STRING 0,"'*******************************************************************************'";
SEND_STRING 0,"'|[HOLD:]'";
SEND_STRING 0,"'| GET_LAST() -Dev:',ITOA(GET_LAST(dvTPs2)),' 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,dvTPs2)),' 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(dvTPs2[RANDOM_NUMBER(5)+1],nUSER_BTN_TEST1[RANDOM_NUMBER(15)+1],5);
}
RELEASE:{
LOCAL_VAR INTEGER x,y;
x = GET_LAST(dvTPs2);
y = GET_LAST(nUSER_BTN_TEST);
SEND_STRING 0,"'-=============================================================================-'";
SEND_STRING 0,"'|[RELEASE:]'";
SEND_STRING 0,"'| GET_LAST() -Dev:',ITOA(GET_LAST(dvTPs2)),' 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,dvTPs2)),' 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,"'/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/'";
}
}
here are the results: (ignore the incorrect button index as I forgot to change the array it is looking at )
Line 1 (18:55:12):: Button 25 was pushed! ********************
Line 2 (18:55:12):: nUSER_BTN_TEST1: GET_LAST() = 5
Line 3 (18:55:12):: ###############################################################################
Line 4 (18:55:12):: |[PUSH:]
Line 5 (18:55:12):: | GET_LAST() -Dev:1 Actual Dev:10001:1:1 | Actual Button Push:25 Get_Last Index:0
Line 6 (18:55:12):: | Variable() -Dev:1 Actual Dev:10001:1:1 | Actual Button Push:25 Get_Last Index:0
Line 7 (18:55:12):: | my() -Dev:1 Actual Dev:10001:1:1 | Actual Button Push:25 myGetLast Index:0
Line 8 (18:55:12):: ###############################################################################
Line 9 (18:55:12):: |[PUSH:]
Line 10 (18:55:12):: | GET_LAST() -Dev:5 Actual Dev:10001:1:1 | Actual Button Push:25 Get_Last Index:0
Line 11 (18:55:12):: | Variable() -Dev:5 Actual Dev:10001:1:1 | Actual Button Push:25 Get_Last Index:0
Line 12 (18:55:12):: | my() -Dev:5 Actual Dev:10001:1:1 | Actual Button Push:25 myGetLast Index:0
Line 13 (18:55:14):: *******************************************************************************
Line 14 (18:55:14):: |[HOLD:]
Line 15 (18:55:14):: | GET_LAST() -Dev:1 Actual Dev:10001:1:1 | Actual Button Hold:25 Get_Last Index:0
Line 16 (18:55:14):: | Variable() -Dev:1 Actual Dev:10001:1:1 | Actual Button Hold:25 Get_Last Index:0
Line 17 (18:55:14):: | my() -Dev:1 Actual Dev:10001:1:1 | Actual Button Hold:25 myGetLast Index:0
Line 18 (18:55:14):: *******************************************************************************
Line 19 (18:55:14):: |[HOLD:]
Line 20 (18:55:14):: | GET_LAST() -Dev:5 Actual Dev:10001:1:1 | Actual Button Hold:25 Get_Last Index:0
Line 21 (18:55:14):: | Variable() -Dev:5 Actual Dev:10001:1:1 | Actual Button Hold:25 Get_Last Index:0
Line 22 (18:55:14):: | my() -Dev:5 Actual Dev:10001:1:1 | Actual Button Hold:25 myGetLast Index:0
Line 23 (18:55:14):: Button 34 was pushed! ********************
Line 24 (18:55:14):: nUSER_BTN_TEST1: GET_LAST() = 14
Line 25 (18:55:14):: ###############################################################################
Line 26 (18:55:14):: |[PUSH:]
Line 27 (18:55:14):: | GET_LAST() -Dev:5 Actual Dev:10005:1:1 | Actual Button Push:34 Get_Last Index:0
Line 28 (18:55:14):: | Variable() -Dev:5 Actual Dev:10005:1:1 | Actual Button Push:34 Get_Last Index:0
Line 29 (18:55:14):: | my() -Dev:5 Actual Dev:10005:1:1 | Actual Button Push:34 myGetLast Index:0
Line 30 (18:55:14):: ###############################################################################
Line 31 (18:55:14):: |[PUSH:]
Line 32 (18:55:14):: | GET_LAST() -Dev:1 Actual Dev:10005:1:1 | Actual Button Push:34 Get_Last Index:0
Line 33 (18:55:14):: | Variable() -Dev:1 Actual Dev:10005:1:1 | Actual Button Push:34 Get_Last Index:0
Line 34 (18:55:14):: | my() -Dev:1 Actual Dev:10005:1:1 | Actual Button Push:34 myGetLast Index:0
Line 35 (18:55:14):: Button 26 was pushed! ********************
Line 36 (18:55:14):: nUSER_BTN_TEST1: GET_LAST() = 6
Line 37 (18:55:14):: ###############################################################################
Line 38 (18:55:14):: |[PUSH:]
Line 39 (18:55:14):: | GET_LAST() -Dev:2 Actual Dev:10002:1:1 | Actual Button Push:26 Get_Last Index:0
Line 40 (18:55:14):: | Variable() -Dev:2 Actual Dev:10002:1:1 | Actual Button Push:26 Get_Last Index:0
Line 41 (18:55:14):: | my() -Dev:2 Actual Dev:10002:1:1 | Actual Button Push:26 myGetLast Index:0
Line 42 (18:55:14):: ###############################################################################
Line 43 (18:55:14):: |[PUSH:]
Line 44 (18:55:14):: | GET_LAST() -Dev:4 Actual Dev:10002:1:1 | Actual Button Push:26 Get_Last Index:0
Line 45 (18:55:14):: | Variable() -Dev:4 Actual Dev:10002:1:1 | Actual Button Push:26 Get_Last Index:0
Line 46 (18:55:14):: | my() -Dev:4 Actual Dev:10002:1:1 | Actual Button Push:26 myGetLast Index:0
Line 47 (18:55:14):: Button 34 was released! ******************
Line 48 (18:55:14):: -=============================================================================-
Line 49 (18:55:14):: |[RELEASE:]
Line 50 (18:55:14):: | GET_LAST() -Dev:5 Actual Dev:10005:1:1 | Actual Button Release:34 Get_Last Index:0
Line 51 (18:55:14):: | Variable() -Dev:5 Actual Dev:10005:1:1 | Actual Button Release:34 Get_Last Index:0
Line 52 (18:55:14):: | my() -Dev:5 Actual Dev:10005:1:1 | Actual Button Release:34 myGetLast Index:0
Line 53 (18:55:14):: /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
Line 54 (18:55:14):: -=============================================================================-
Line 55 (18:55:14):: |[RELEASE:]
Line 56 (18:55:14):: | GET_LAST() -Dev:1 Actual Dev:10005:1:1 | Actual Button Release:34 Get_Last Index:0
Line 57 (18:55:14):: | Variable() -Dev:1 Actual Dev:10005:1:1 | Actual Button Release:34 Get_Last Index:0
Line 58 (18:55:14):: | my() -Dev:1 Actual Dev:10005:1:1 | Actual Button Release:34 myGetLast Index:0
Line 59 (18:55:14):: /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
Line 60 (18:55:14):: Button 26 was released! ******************
Line 61 (18:55:14):: -=============================================================================-
Line 62 (18:55:14):: |[RELEASE:]
Line 63 (18:55:14):: | GET_LAST() -Dev:2 Actual Dev:10002:1:1 | Actual Button Release:26 Get_Last Index:0
Line 64 (18:55:14):: | Variable() -Dev:2 Actual Dev:10002:1:1 | Actual Button Release:26 Get_Last Index:0
Line 65 (18:55:14):: | my() -Dev:2 Actual Dev:10002:1:1 | Actual Button Release:26 myGetLast Index:0
Line 66 (18:55:14):: /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
Line 67 (18:55:14):: -=============================================================================-
Line 68 (18:55:14):: |[RELEASE:]
Line 69 (18:55:14):: | GET_LAST() -Dev:4 Actual Dev:10002:1:1 | Actual Button Release:26 Get_Last Index:0
Line 70 (18:55:14):: | Variable() -Dev:4 Actual Dev:10002:1:1 | Actual Button Release:26 Get_Last Index:0
Line 71 (18:55:14):: | my() -Dev:4 Actual Dev:10002:1:1 | Actual Button Release:26 myGetLast Index:0
Line 72 (18:55:14):: /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
Line 73 (18:55:16):: *******************************************************************************
Line 74 (18:55:16):: |[HOLD:]
Line 75 (18:55:16):: | GET_LAST() -Dev:2 Actual Dev:10001:1:1 | Actual Button Hold:25 Get_Last Index:0
Line 76 (18:55:16):: | Variable() -Dev:2 Actual Dev:10001:1:1 | Actual Button Hold:25 Get_Last Index:0
Line 77 (18:55:16):: | my() -Dev:1 Actual Dev:10001:1:1 | Actual Button Hold:25 myGetLast Index:0
Line 78 (18:55:16):: *******************************************************************************
Line 79 (18:55:16):: |[HOLD:]
Line 80 (18:55:16):: | GET_LAST() -Dev:4 Actual Dev:10001:1:1 | Actual Button Hold:25 Get_Last Index:0
Line 81 (18:55:16):: | Variable() -Dev:4 Actual Dev:10001:1:1 | Actual Button Hold:25 Get_Last Index:0
Line 82 (18:55:16):: | my() -Dev:5 Actual Dev:10001:1:1 | Actual Button Hold:25 myGetLast Index:0
Line 83 (18:55:16):: Button 22 was pushed! ********************
Line 84 (18:55:16):: nUSER_BTN_TEST1: GET_LAST() = 2
Line 85 (18:55:16):: ###############################################################################
Line 86 (18:55:16):: |[PUSH:]
Line 87 (18:55:16):: | GET_LAST() -Dev:4 Actual Dev:10004:1:1 | Actual Button Push:22 Get_Last Index:0
Line 88 (18:55:16):: | Variable() -Dev:4 Actual Dev:10004:1:1 | Actual Button Push:22 Get_Last Index:0
Line 89 (18:55:16):: | my() -Dev:4 Actual Dev:10004:1:1 | Actual Button Push:22 myGetLast Index:0
Line 90 (18:55:16):: ###############################################################################
Line 91 (18:55:16):: |[PUSH:]
Line 92 (18:55:16):: | GET_LAST() -Dev:2 Actual Dev:10004:1:1 | Actual Button Push:22 Get_Last Index:0
Line 93 (18:55:16):: | Variable() -Dev:2 Actual Dev:10004:1:1 | Actual Button Push:22 Get_Last Index:0
Line 94 (18:55:16):: | my() -Dev:2 Actual Dev:10004:1:1 | Actual Button Push:22 myGetLast Index:0
Line 95 (18:55:16):: Button 30 was pushed! ********************
Line 96 (18:55:16):: nUSER_BTN_TEST1: GET_LAST() = 10
Line 97 (18:55:16):: ###############################################################################
Line 98 (18:55:16):: |[PUSH:]
Line 99 (18:55:16):: | GET_LAST() -Dev:5 Actual Dev:10005:1:1 | Actual Button Push:30 Get_Last Index:0
Line 100 (18:55:16):: | Variable() -Dev:5 Actual Dev:10005:1:1 | Actual Button Push:30 Get_Last Index:0
Line 101 (18:55:16):: | my() -Dev:5 Actual Dev:10005:1:1 | Actual Button Push:30 myGetLast Index:0
Line 102 (18:55:16):: ###############################################################################
Line 103 (18:55:16):: |[PUSH:]
Line 104 (18:55:16):: | GET_LAST() -Dev:1 Actual Dev:10005:1:1 | Actual Button Push:30 Get_Last Index:0
Line 105 (18:55:16):: | Variable() -Dev:1 Actual Dev:10005:1:1 | Actual Button Push:30 Get_Last Index:0
Line 106 (18:55:16):: | my() -Dev:1 Actual Dev:10005:1:1 | Actual Button Push:30 myGetLast Index:0
Line 107 (18:55:16):: Button 22 was released! ******************
Line 108 (18:55:16):: -=============================================================================-
Line 109 (18:55:16):: |[RELEASE:]
Line 110 (18:55:16):: | GET_LAST() -Dev:4 Actual Dev:10004:1:1 | Actual Button Release:22 Get_Last Index:0
Line 111 (18:55:16):: | Variable() -Dev:4 Actual Dev:10004:1:1 | Actual Button Release:22 Get_Last Index:0
Line 112 (18:55:16):: | my() -Dev:4 Actual Dev:10004:1:1 | Actual Button Release:22 myGetLast Index:0
Line 113 (18:55:16):: /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
Line 114 (18:55:16):: -=============================================================================-
Line 115 (18:55:16):: |[RELEASE:]
Line 116 (18:55:16):: | GET_LAST() -Dev:2 Actual Dev:10004:1:1 | Actual Button Release:22 Get_Last Index:0
Line 117 (18:55:16):: | Variable() -Dev:2 Actual Dev:10004:1:1 | Actual Button Release:22 Get_Last Index:0
Line 118 (18:55:16):: | my() -Dev:2 Actual Dev:10004:1:1 | Actual Button Release:22 myGetLast Index:0
Line 119 (18:55:16):: /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
Line 120 (18:55:16):: Button 30 was released! ******************
Line 121 (18:55:16):: -=============================================================================-
Line 122 (18:55:16):: |[RELEASE:]
Line 123 (18:55:16):: | GET_LAST() -Dev:5 Actual Dev:10005:1:1 | Actual Button Release:30 Get_Last Index:0
Line 124 (18:55:16):: | Variable() -Dev:5 Actual Dev:10005:1:1 | Actual Button Release:30 Get_Last Index:0
Line 125 (18:55:16):: | my() -Dev:5 Actual Dev:10005:1:1 | Actual Button Release:30 myGetLast Index:0
Line 126 (18:55:16):: /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
Line 127 (18:55:16):: -=============================================================================-
Line 128 (18:55:16):: |[RELEASE:]
Line 129 (18:55:16):: | GET_LAST() -Dev:1 Actual Dev:10005:1:1 | Actual Button Release:30 Get_Last Index:0
Line 130 (18:55:16):: | Variable() -Dev:1 Actual Dev:10005:1:1 | Actual Button Release:30 Get_Last Index:0
Line 131 (18:55:16):: | my() -Dev:1 Actual Dev:10005:1:1 | Actual Button Release:30 myGetLast Index:0
Line 132 (18:55:16):: /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
Line 133 (18:55:18):: *******************************************************************************
Line 134 (18:55:18):: |[HOLD:]
Line 135 (18:55:18):: | GET_LAST() -Dev:5 Actual Dev:10001:1:1 | Actual Button Hold:25 Get_Last Index:0
Line 136 (18:55:18):: | Variable() -Dev:5 Actual Dev:10001:1:1 | Actual Button Hold:25 Get_Last Index:0
Line 137 (18:55:18):: | my() -Dev:1 Actual Dev:10001:1:1 | Actual Button Hold:25 myGetLast Index:0
Line 138 (18:55:18):: *******************************************************************************
Line 139 (18:55:18):: |[HOLD:]
Line 140 (18:55:18):: | GET_LAST() -Dev:1 Actual Dev:10001:1:1 | Actual Button Hold:25 Get_Last Index:0
Line 141 (18:55:18):: | Variable() -Dev:1 Actual Dev:10001:1:1 | Actual Button Hold:25 Get_Last Index:0
Line 142 (18:55:18):: | my() -Dev:5 Actual Dev:10001:1:1 | Actual Button Hold:25 myGetLast Index:0
Line 143 (18:55:18):: Button 34 was pushed! ********************
Line 144 (18:55:18):: nUSER_BTN_TEST1: GET_LAST() = 14
Line 145 (18:55:18):: ###############################################################################
Line 146 (18:55:18):: |[PUSH:]
Line 147 (18:55:18):: | GET_LAST() -Dev:3 Actual Dev:10003:1:1 | Actual Button Push:34 Get_Last Index:0
Line 148 (18:55:18):: | Variable() -Dev:3 Actual Dev:10003:1:1 | Actual Button Push:34 Get_Last Index:0
Line 149 (18:55:18):: | my() -Dev:3 Actual Dev:10003:1:1 | Actual Button Push:34 myGetLast Index:0
Line 150 (18:55:18):: ###############################################################################
Line 151 (18:55:18):: |[PUSH:]
Line 152 (18:55:18):: | GET_LAST() -Dev:3 Actual Dev:10003:1:1 | Actual Button Push:34 Get_Last Index:0
Line 153 (18:55:18):: | Variable() -Dev:3 Actual Dev:10003:1:1 | Actual Button Push:34 Get_Last Index:0
Line 154 (18:55:18):: | my() -Dev:3 Actual Dev:10003:1:1 | Actual Button Push:34 myGetLast Index:0
Line 155 (18:55:18):: Button 22 was pushed! ********************
Line 156 (18:55:18):: nUSER_BTN_TEST1: GET_LAST() = 2
Line 157 (18:55:18):: ###############################################################################
Line 158 (18:55:18):: |[PUSH:]
Line 159 (18:55:18):: | GET_LAST() -Dev:2 Actual Dev:10002:1:1 | Actual Button Push:22 Get_Last Index:0
Line 160 (18:55:18):: | Variable() -Dev:2 Actual Dev:10002:1:1 | Actual Button Push:22 Get_Last Index:0
Line 161 (18:55:18):: | my() -Dev:2 Actual Dev:10002:1:1 | Actual Button Push:22 myGetLast Index:0
Line 162 (18:55:18):: ###############################################################################
Line 163 (18:55:18):: |[PUSH:]
Line 164 (18:55:18):: | GET_LAST() -Dev:4 Actual Dev:10002:1:1 | Actual Button Push:22 Get_Last Index:0
Line 165 (18:55:18):: | Variable() -Dev:4 Actual Dev:10002:1:1 | Actual Button Push:22 Get_Last Index:0
Line 166 (18:55:18):: | my() -Dev:4 Actual Dev:10002:1:1 | Actual Button Push:22 myGetLast Index:0
Line 167 (18:55:18):: Button 25 was released! ******************
Line 168 (18:55:18):: -=============================================================================-
Line 169 (18:55:18):: |[RELEASE:]
Line 170 (18:55:18):: | GET_LAST() -Dev:1 Actual Dev:10001:1:1 | Actual Button Release:25 Get_Last Index:0
Line 171 (18:55:18):: | Variable() -Dev:1 Actual Dev:10001:1:1 | Actual Button Release:25 Get_Last Index:0
Line 172 (18:55:18):: | my() -Dev:1 Actual Dev:10001:1:1 | Actual Button Release:25 myGetLast Index:0
Line 173 (18:55:18):: /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
Line 174 (18:55:18):: -=============================================================================-
Line 175 (18:55:18):: |[RELEASE:]
Line 176 (18:55:18):: | GET_LAST() -Dev:5 Actual Dev:10001:1:1 | Actual Button Release:25 Get_Last Index:0
Line 177 (18:55:18):: | Variable() -Dev:5 Actual Dev:10001:1:1 | Actual Button Release:25 Get_Last Index:0
Line 178 (18:55:18):: | my() -Dev:5 Actual Dev:10001:1:1 | Actual Button Release:25 myGetLast Index:0
Line 179 (18:55:18):: /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
Line 180 (18:55:18):: Button 34 was released! ******************
Line 181 (18:55:18):: -=============================================================================-
Line 182 (18:55:18):: |[RELEASE:]
Line 183 (18:55:18):: | GET_LAST() -Dev:3 Actual Dev:10003:1:1 | Actual Button Release:34 Get_Last Index:0
Line 184 (18:55:18):: | Variable() -Dev:3 Actual Dev:10003:1:1 | Actual Button Release:34 Get_Last Index:0
Line 185 (18:55:18):: | my() -Dev:3 Actual Dev:10003:1:1 | Actual Button Release:34 myGetLast Index:0
Line 186 (18:55:18):: /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
Line 187 (18:55:18):: -=============================================================================-
Line 188 (18:55:18):: |[RELEASE:]
Line 189 (18:55:18):: | GET_LAST() -Dev:3 Actual Dev:10003:1:1 | Actual Button Release:34 Get_Last Index:0
Line 190 (18:55:18):: | Variable() -Dev:3 Actual Dev:10003:1:1 | Actual Button Release:34 Get_Last Index:0
Line 191 (18:55:18):: | my() -Dev:3 Actual Dev:10003:1:1 | Actual Button Release:34 myGetLast Index:0
Line 192 (18:55:18):: /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
Line 193 (18:55:18):: Button 22 was released! ******************
Line 194 (18:55:18):: -=============================================================================-
Line 195 (18:55:18):: |[RELEASE:]
Line 196 (18:55:18):: | GET_LAST() -Dev:2 Actual Dev:10002:1:1 | Actual Button Release:22 Get_Last Index:0
Line 197 (18:55:18):: | Variable() -Dev:2 Actual Dev:10002:1:1 | Actual Button Release:22 Get_Last Index:0
Line 198 (18:55:18):: | my() -Dev:2 Actual Dev:10002:1:1 | Actual Button Release:22 myGetLast Index:0
Line 199 (18:55:18):: /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
Line 200 (18:55:18):: -=============================================================================-
Line 201 (18:55:18):: |[RELEASE:]
Line 202 (18:55:18):: | GET_LAST() -Dev:4 Actual Dev:10002:1:1 | Actual Button Release:22 Get_Last Index:0
Line 203 (18:55:18):: | Variable() -Dev:4 Actual Dev:10002:1:1 | Actual Button Release:22 Get_Last Index:0
Line 204 (18:55:18):: | my() -Dev:4 Actual Dev:10002:1:1 | Actual Button Release:22 myGetLast Index:0
Line 205 (18:55:18):: /\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/
As in my other tests, myGetLast functions worked properly in all events including the Hold event. No variable needed.
Now that I think about it, when you are using variables to track the current hold buttons, are you creating a seperate tracking array for each and every button event, or are you using one array for all button event tracking?
Jeff,
Either you did something terribly wrong, or I did . . . not sure how I get the "correct" index every time and yours returns 0 every time.....
Anyway . . . I really don't think there is a problem at all with GET_LAST, I feel it's how you use it. If you try to use the GET_LAST value outside of the event that calls it, well . . . expect problems. Otherwise, if it's used within the same event (except HOLD), then it will always return the correct event.
I still don't see why people still use the HOLD event when it has such limitations. There are more flexible substitutes of REPEAT (using timelines), and the whole setting of presets using WAITs and CANCEL_WAITs, and I for one intend to make every system as flexible as possible, because when someone wants to add several more touch panels to the system, all I want to do is make a few definitions, and move on with life - not rewrite the entire code.
Comments
It appeared to me that putting blocking VAR in the push even if I did it right wouldn't work because the release would have changed the values as well if some one else pushed/released a TP's button that ran through this code block while a HOLD was in progress on another TP. So I had to modify the way that worked as well.
This revision doesn't actually block further pushes or releases any more either but simple holds the HOLD values for use during a hold and then compares release values to the hold values to determine if the correct (BTN being held) button was released. So if my thinking is correct other TPs can still use this code while a hold is in progress and there should be no negative outcome.
The only thing I'm not sure of is what happens when another TP using this same device/code HOLDs a button at the same time. My thinking is that nothing will happen, no second hold taking over or changing values since the hold is affectively a wait. My thinking that since a "HOLD" wait is pending another attemp to "HOLD" wait will simply be disregarded.
Paul
The question is does the system treat the hold like a system named wait or in other words any wait in the system that isn't explicitly named by us. Then I would think in the code I just posted that the second hold would be ignored since the wait is already pending. Of course If I had time I could test it but that not going to happen any time soon.
I don't agree, but obviously its a judgement call. A user can't expect a device to respond to two holds at the same time from two different UIs so the question is what should happen in that event.
You can do as you do, and block a user from being able to trigger a hold, and popping up your "Please wait...System busy" popup, annoying the user further and adding to their confusion as to why the device isn't responding correctly. Or you can just not do anything, and let the system sort it out for you, in which case if a user is holding a button and it mysteriously stops holding its fairly obvious someone else has taken control from you and you will have to hit the button again if you want to regain control.
This scenario means that whoever hit a button on a UI most recently, has control, which is more consistent to me than whoever hit a button most recently has control unless someone is holding a button and then you are blocked until all users release that button, and you have cleared your "Please wait...System busy" popup, by which time someone has hit hold again so you get the popup again, and so on and so on, until you are so tired and confused you turn off the TV and go to bed.
My way means noone is ever denied control when they ask for it, but it may impinge on another user should they be using a hold when you want to as well. C'est la vie n'est-pa?
Paul
Actually the method I most recently posted doesn't use a "Please Wait" and although not tested it should allow both users to do pushes even if one person is holding. My only thought was if the second person tried a hold while the first person was holding, the second hold wouldn't execute the way my code is written but that depends on how the system evaluates the hold, is it like a wait or not? I think that's prefferable to the dueling hold method since we're only talking about a second or two of waiting. Plus individual button pushes would still work and most folks aren't even aware that they can actually do holds anyway.
So when two users try to change their respective audio zones off of an Autopatch or anything other RS-232 device, someone should get locked out? I beg to differ. Things like that are EASILY avoidable with timelines. Fire a timeline off for each zone that's trying to adjusted.
Now, two users trying to control the same IR device, that's a different story, but then again - how often is someone going to try to control the same satellite box, or cable box, or anything else that's IR? And you know, if it's explained to the users well enough, there will never be a problem. The users need to know the limitations. Period.
I use the number of outputs on whatever audio switcher we're using (usually an 18x18 Autopatch.) So there are always at least 18 timelines, even if at the moment we're using 10 of those outputs (allows for expandability.) Now of course, no two people can control the same zone at the same time (i.e. one wants to go up, the other wants to go down), but again - that's just an obvious limitation of the system the user needs to understand.
Here's a code snippet:
In your volume code, I am assuming you are not using the AP Duet module? I guess I am confused why you are using a timeline to control volume on a RS232 switch? I guess I haven't encountered the problem you are trying to solve.
Paul
Instead of jumping the gun and shooting your mouth off like usual, allow me to quote myself: Translation:
I know you can't control an IR device with more than two codes at the same time, which is a limitation of the system and needs to be explained to the client. Period.
No - I don't use modules with devices I use time and time again. I prefer to use my own code, as they're usually way too bloated and rarely achieve what I'm trying to do.
How else do you plan on doing it? Instead of criticizing everything, why not pony up the "perfect" code you use?
Ok
Woah...no need for the ad hominem attack, they were just some simple questions.
Yes, but that wasn't my question. There are apparently at least two different ways of dealing with this, one is the way Vinning recommends which is to block other users, and the way I do it which is to always give control to the last user in a hold and not block. You didn't answer the question of what your method does in that instance.
I use the AMX AP module which seems to deal with this quite well so it isn't a problem I have come across. Perhaps your module is dealing with that situation differently and so you encounter the issue more regularly.
Paul
My posted method does nothing with IR.
Maybe I didn't answer the question because I *very rarely* use HOLD events, and never to control a device.
Not an ad hominem "attack", I was just saying - read what I wrote, perhaps just a little on the brash side though.
If you assign the result of get_last to a variable then there should be no problem, like Dave mentions. Since the result is in a variable, it doesn't matter if another panel uses the same hold code since it will be operating on a different variable. From the testing I have done, get_last will return the last touch panel button pressed system-wide.
I don't understand why you would write functions that duplicate built-in functions. get_last probably has access to a pointer that you don't have access to, and hence you have to search arrays in linear time.
There is no point in calling get_last in a hold event because its return value could be a different panel/channel/etc than the one that caused the push you are holding on. That is the point of storing it in a variable.
All of the tests I ran with the built-in GET_LAST indicate that it is doing the same thing my function does, only it seems to be overloaded in that you can pass it an array of integers or an array of devices. For some reason, it also does not function properly on a hold. The functions I wrote do work properly in a hold event.
Now that I think about it, GET_LAST does work a little differently than my function. It is obviously tracking all of these events somewhere as you can call GET_LAST from anywhere and it will return the last value for the array you pass it. In order for my functions to work the same way, you would need to create tracking variables for every array you want to track, then update the tracking variables when ever an event occurs that involves a member of every array being tracked. This would actually add a lot of overhead and it would in fact cause the same problems that currently exist in GET_LAST. This raises a question: Does the processor ALWAYS track this information, or does it build these tracking variables only when a GET_LAST is used in code?
The reason I initially wrote the modules was to explore and enhance my understanding of the NetLinx processor and its functionality. After writing the functions, and seeing that they work, I have decided to use them because they let me easily update some old code that was written with GET_LAST. This is code that has been working fine, but the possibility did exist in which it would not function properly. By using a get_last that functions properly, I don't have to revisit or rewrite the rest of the code. This means less chance of screwing up functional code because I already tested the new functions and I haven't changed any of the other code.
In the end, I just developed a different way to skin the cat. It seems to me that your approach to deal with the flaws in GET_LAST is by writing additional code that is written to overcome the flaws. My approach is to simply fix the flaws in GET_LAST. Which way is correct? I would say both. A lot depends on what you are trying to accomplish. It sounds like your approach does add some other functionality, but in the situation I was faced with, I didn't need more, I just needed it to function the same in all cases. I consider my new functions as new tools in my tool box, I just need to know when to use them.
Jeff
I'd prefer an Eminem attack... they tend rhyme and are done to a beat :P
Jeff
Just think about it.
Anyway, back on subject . . . I have a question for the users of B.I.C., when writing an event, do you use the actual button number in the definition of the button event, or do you define a constant and use that instead?
I don't know if I would characterize it the way you are. I don't think there are any flaws in get_last per se. It does what it is supposed to do. The problem is the way a hold is implemented, in that the system doesn't know when a hold is actually occurring, it just assumes a hold is taking place when a push with no release happens. get_last cannot return the correct value in a hold since no hardware event occurs for a hold. Since a hold can go on for some time while other touch panels are being used, the value that get_last returns will change while you are processing the hold. The way around this is to save the result from get_last in the push and use it in the hold. That way it won't matter if three people are all holding the same button on three different UIs because the hold will process a different variable for each. You don't really need to write new functions, but of course you can if you want to. Rewriting system functions can have unintended consequences so you might find other bugs.
Paul
Of course the likely hood of any of this really happening on any of my system is so rare it's not worth fussing about but having the knowledge should I choose to use it was worth the trip.
I'd think you'd WANT to know when 5 kids were holding the same button, so that your control system could summon Captain Planet...
Lol...You sound like my boss. I always have the argument with him that rarity of an event shouldn't determine whether it works or not.
Paul
If you have two button events that have two different TP arrays, but there is an identical TP defined in each one, will get_last return different values for each button event?
If get_last is implemented correctly, it should return two different values in each button event when button 10 is pressed on dvTP2.
Paul
Results:
Multiple events are fired if the same button number and device code are defined, hence why sometimes you may get a double pulse or something with IR if one forgets to remove a specific statement from their code (an error I've made plenty of times when I first started coding.)
The results should not come as a surprise.
Push and Release function the way you describe. Hold is still subjected to the same limitations.
Here is the code I used:
here are the results: (ignore the incorrect button index as I forgot to change the array it is looking at )
As in my other tests, myGetLast functions worked properly in all events including the Hold event. No variable needed.
Now that I think about it, when you are using variables to track the current hold buttons, are you creating a seperate tracking array for each and every button event, or are you using one array for all button event tracking?
Jeff
Either you did something terribly wrong, or I did . . . not sure how I get the "correct" index every time and yours returns 0 every time.....
Anyway . . . I really don't think there is a problem at all with GET_LAST, I feel it's how you use it. If you try to use the GET_LAST value outside of the event that calls it, well . . . expect problems. Otherwise, if it's used within the same event (except HOLD), then it will always return the correct event.
I still don't see why people still use the HOLD event when it has such limitations. There are more flexible substitutes of REPEAT (using timelines), and the whole setting of presets using WAITs and CANCEL_WAITs, and I for one intend to make every system as flexible as possible, because when someone wants to add several more touch panels to the system, all I want to do is make a few definitions, and move on with life - not rewrite the entire code.