Home AMX User Forum AMX Technical Discussion

Button_event[TP,0]

AMX recommends against using button press 0. Does anyone know why?

Comments

  • TurnipTruckTurnipTruck Posts: 1,485
    Hi Ken,

    I have never heard them recommend against it. I have seen it used in some of their examples, especially those explaining select..active amd switch..case.

    I use ,0 all the time and have never suffered for it.
  • John NagyJohn Nagy Posts: 1,742
    We've used x,o on every non-button entity on panels since the beginning. For buttons uses as a static graphic, for text that is dynamic but not a button, for page flips (though we do that rarely, we let the program drive). I'd like to know more about the recommendation you mention... I think there's a misunderstanding. Perhaps the point was that a x,0 does not create a button event, thus being useless to watch for...?

    [edit - Later I got the point that the OP was programming side, not panel side, my mistake]
  • The problem

    AMX explained that programming a button_event[dvaTP,0] creates a button events for the maximum about of button events per TP. It something like 2000 events per port per TP. It quickly consumes memory. That why they recommend caution. The DevArray of TPs could be 20 to 50 touch panels. I didn't know this...
  • John NagyJohn Nagy Posts: 1,742
    I think we're talking about different ends of the rope. You've clarified (and this time I get it) that the warning is about use of the call for the event in programming; use of the 0 port on touch panels for buttons you don't care to hear from isn't a problem.

    We'll do some testing and see what we get with this declaration compared to the arrays we presently use to validate what buttons we care to hear from. I'll let you know.
  • viningvining Posts: 4,368
    kbeattyAMX wrote: »
    AMX explained that programming a button_event[dvaTP,0] creates a button events for the maximum about of button events per TP. It something like 2000 events per port per TP. It quickly consumes memory. That why they recommend caution. The DevArray of TPs could be 20 to 50 touch panels. I didn't know this...

    I was specially told in a post by one of the senior engineers that frequent this forum that the opposite is true and it in fact uses less resources then any thing else. I'll see if I can find the post.
  • John NagyJohn Nagy Posts: 1,742
    Testing here shows no ill effect and considerable memory saving of using [Tp,0] instead of specifically declared arrays for input. Some restructuring to do to convert to this method but the savings appear worth a rethink. Also saves on boot time.

    Thanks for surfacing this issue and answer, we may move to this model after more testing.
  • banobano Posts: 173
    John Nagy wrote: »
    Testing here shows no ill effect and considerable memory saving of using [Tp,0] instead of specifically declared arrays for input. Some restructuring to do to convert to this method but the savings appear worth a rethink. Also saves on boot time.

    Thanks for surfacing this issue and answer, we may move to this model after more testing.

    The "wild card" works very well when dedicating a port to specific device, such as a lutron lighting.

    define_call 'send light button push' (integer intProc, integer intLink, integer intButtonChannel)
    stack_var integer intKeypad
    stack_var integer intButton
    {
    intKeypad = (intButtonChannel / 100)
    intButton = (intButtonChannel % 100)
    send_command vHWI,"'K:P::',itoa(intButton)"
    }

    button_event[vdvModero5,0]
    {
    push:
    call 'send light button push' (1,6,button.input.channel)
    }

    If you want to push button 6 on lighting keypad 24, than your button channel value would be 2406.
  • a_riot42a_riot42 Posts: 1,624
    bano wrote: »
    The "wild card" works very well when dedicating a port to specific device, such as a lutron lighting.

    define_call 'send light button push' (integer intProc, integer intLink, integer intButtonChannel)
    stack_var integer intKeypad
    stack_var integer intButton
    {
    intKeypad = (intButtonChannel / 100)
    intButton = (intButtonChannel % 100)
    send_command vHWI,"'K:P::',itoa(intButton)"
    }

    button_event[vdvModero5,0]
    {
    push:
    call 'send light button push' (1,6,button.input.channel)
    }

    If you want to push button 6 on lighting keypad 24, than your button channel value would be 2406.

    All those expensive / and % calculations for every button event? Seems wasteful to me. Why not just use strings instead of the math.
    define_call 'send light button push' (integer intProc, integer intLink, char sButtonChannel[])
    {
      send_command vHWI,"'K:P:[',itoa(intProc),':',itoa(intLink),':', get_buffer_string(sButtonChannel, 2),']:',sButtonChannel" 
    }
    
    button_event[vdvModero5,0]
    {
      push:
        call 'send light button push' (1, 6, itoa(button.input.channel))
     }
    
    

    Paul
  • This is interesting. I have been using math interpretation of the button channel without considering the string manipulation approach. Are we totally sure that a string find/extract is lighter or better than a math division operation?

    Can you clarify "expensive" "wasteful" please?
  • This is interesting...Are we totally sure that a string find/extract is lighter or better than a math division operation?

    Can you clarify "expensive" "wasteful" please?

    I am wondering the same thing. I've never heard that math operations are slower than string functions.
  • So is there any difference between :
    BUTTON_EVENT [dvTPCABLE,BUTTON.INPUT.CHANNEL]
    {
    PUSH:
      {
      PULSE [dvCABLE_IR,BUTTON.INPUT.CHANNEL]
      }
    }
    

    or
    BUTTON_EVENT [dvTPCABLE,0]
    {
    PUSH:
      {
      PULSE [dvCABLE_IR,BUTTON.INPUT.CHANNEL]
      }
    }
    
    
    ?
    Do these methods create and use the same amount of memory? Is the memory savings only when using button events based on declared arrays?
  • a_riot42 wrote: »
    All those expensive / and % calculations for every button event? Seems wasteful to me. Why not just use strings instead of the math.
    define_call 'send light button push' (integer intProc, integer intLink, char sButtonChannel[])
    {
      send_command vHWI,"'K:P:[',itoa(intProc),':',itoa(intLink),':', get_buffer_string(sButtonChannel, 2),']:',sButtonChannel" 
    }
    
    button_event[vdvModero5,0]
    {
      push:
        call 'send light button push' (1, 6, itoa(button.input.channel))
     }
    
    

    Paul

    To add another spin, which saves more memory? Having a port on a panel with 2406+ channels being used, or using a string sent from each button with the ASCII characters in it to redirect to the function?
    data_event[vdvModero5]
    {
      string:
        {
        stack_var CHAR cCHANNEL [4]
        cCHANNEL = DATA.TEXT
        call 'send light button push' (1, 6,cCHANNEL)
        }
     }
    
  • mpullinmpullin Posts: 949
    PHSJason wrote: »
    So is there any difference between :
    BUTTON_EVENT [dvTPCABLE,BUTTON.INPUT.CHANNEL]
    {
    PUSH:
      {
      PULSE [dvCABLE_IR,BUTTON.INPUT.CHANNEL]
      }
    }
    

    or
    BUTTON_EVENT [dvTPCABLE,0]
    {
    PUSH:
      {
      PULSE [dvCABLE_IR,BUTTON.INPUT.CHANNEL]
      }
    }
    
    
    ?
    Yes. The former is not possible.
    The BUTTON.INPUT structure is only accessible inside of a button event.

    BUTTON_EVENT [dvTPCABLE,0] will catch all presses on touchpanel dvTPCABLE. BUTTON_EVENT [dvTPCABLE,5] will only catch button channel 5 being pressed. BUTTON_EVENT [dvTPCABLE,arrONETHRUTEN] will only catch button channels 1 - 10, assuming arrONETHRUTEN is defined as integer array {1,2,3,4,5,6,7,8,9,10}

    Hope that clears some things up.
  • viningvining Posts: 4,368
    PHSJason wrote: »
    So is there any difference between :
    BUTTON_EVENT [dvTPCABLE,BUTTON.INPUT.CHANNEL]
    {
    PUSH:
      {
      PULSE [dvCABLE_IR,BUTTON.INPUT.CHANNEL]
      }
    }
    

    or
    BUTTON_EVENT [dvTPCABLE,0]
    {
    PUSH:
      {
      PULSE [dvCABLE_IR,BUTTON.INPUT.CHANNEL]
      }
    }
    
    
    ?
    Do these methods create and use the same amount of memory? Is the memory savings only when using button events based on declared arrays?
    BUTTON_EVENT [dvTPCABLE,BUTTON.INPUT.CHANNEL]
    What is the value of BUTTON.INPUT.CHANNEL when the event table is created? Should be 0 after a reload/reboot but may hold any number of values depending on what the last button channel is/was if anything happened before the table was created since it is global value. It will probably be 0 but if that's what you want then use 0 since using BUTTON.INPUT.CHANNEL in this way is kind of an accident waiting to happen.
  • a_riot42a_riot42 Posts: 1,624
    This is interesting. I have been using math interpretation of the button channel without considering the string manipulation approach. Are we totally sure that a string find/extract is lighter or better than a math division operation?

    Can you clarify "expensive" "wasteful" please?

    You can test it easily enough. I haven't, but typically the modulus operator is inefficient, especially in embedded systems. Since you have to send a string to the module anyway, there seems to be no point in using integers, and doing calculations on them. You aren't searching for a string, you are just referencing the first two elements, so its a low cost operation. Expensive means uses lots of CPU ops, wasteful means using lots of CPU ops when a much less expensive way is available that also requires less code. Probably won't make much difference, but I never use modulus unless there is no other choice for this reason so I thought I would mention it.
    Paul
  • PhreaKPhreaK Posts: 966
    Paul's on the money with this. You're not actually needing to do any string manipulation, just referencing characters in an array. If you were uber worried about efficiency you could try this
    send_command vHWI,"'K:P:[',itoa(intProc),':',itoa(intLink),':',sButtonChannel[1],sButtonChannel[2],']:',sButtonChannel[3],sButtonChannel[4]"
    
    so that you are not having to manipulate the array with a get_buffer_char. With both these solution keep in mind that you will top out at 99 keypads and each with 99 buttons.

    Alternatively, if you *really* needed that bit of extra performance you could sacrifice come usability for yourself when you're coding and define your button numbers with something that fits nicely in base 2. For positive numbers x % 2^n == x & (2^n - 1). This will then allow you to do a bitwise AND rather than a modulus in your button event.

    For example, if you wanted to set a limit of say 255 keypads, each with 255 buttons you code in the button event would be
    keypad = buttonChannel >> 8
    button = buttonChannel & 255
    
    To have a button representing button 7 on keypad 2 it would be given the channel number 519 (0x0207), or if you were able to work with arrays of buttons and keys with the first element at 0: 262 (0x0106) which would allow you to have up to 256. Personally though if I came across this in an adopted project I would want to track down the original developer and beat them, repeatedly. Also, if you then convert this to a string to send it to your module you just negated any efficiency gained by this approach.
  • Thanks guys. The pourdown of arguments is really convincing.
    However, instead of so many "how one can do it with strings" I was more expecting a clear and documented "why one would rather do it with strings".
    For me they both work, none gives problems, I just picked one that came first... It was Paul's confidence that made me look for more insight and a better explanation as of why this is wasteful.
    I don't know how AMX does it, but it seems like some paradigms of converting an integer to an array of chars still use the modulo, which was the essence of my question.
    http://en.wikipedia.org/wiki/Itoa
  • a_riot42a_riot42 Posts: 1,624
    I don't know how AMX does it, but it seems like some paradigms of converting an integer to an array of chars still use the modulo, which was the essence of my question.

    I'm not sure how AMX does it either, but you could also use format or come up with a different scheme not requiring itoa, but it actually brings up another issue that is probably more important than that anyway. I decouple the button channels from anything else so that these things never occur. I never use the channel number in any part of a calculation to do something or to refer to a value. Its like a magic number, and I stay away from them. Typically I use the index to an array and the channel number is only used to trigger the event and nothing else. I see a lot of code that has bizarre arithmetic/math calculations based on the channel number and its just a bug fiesta when you do that. I'm sure we've all seen code like this:
    button_event[dvTP, 0]
    {
      push:
      {
        pulse[dvDevice, button.input.channel + 117 - cnBtnOffset * 2 / cnMaxZones - cnNumZones + 1] 
      }
    }
    

    This kind of thing just gives me the heebie jeebies.
    Paul
  • Paul. You don't get the point. You made a statement and I asked you a favor to explain, only thinking that nobody would be condescending before knowing all the facts. Again, we all know there are many ways of doing something, the discussion was about "I say doing it that way is wrong". Please take this as a humble clarification requested from somebody who seems to have more knowledge, under a topic where best efficient practices are being freely discussed.
  • a_riot42a_riot42 Posts: 1,624
    Paul. You don't get the point. You made a statement and I asked you a favor to explain, only thinking that nobody would be condescending before knowing all the facts. Again, we all know there are many ways of doing something, the discussion was about "I say doing it that way is wrong". Please take this as a humble clarification requested from somebody who seems to have more knowledge, under a topic where best efficient practices are being freely discussed.

    I never said it was wrong, just potentially expensive and wasteful. Ultimately you need a string to send in your command so I don't see the point in doing math on integers to generate a string. But I am sure it will work, as long as you have less than 39 keypads. If you have 40 or more, your code wouldn't work.

    Your original code uses 4 itoa calls, a division and modulo to send a send a string to a lighting controller. That seems a little over the top to me so I thought I would mention it in case you weren't aware.
    Paul
  • Thanks Paul. That code is not my code. Assuming that AMX uses K&R implementation of ITOA, we have as many %operations as digits in the channel before even getting to a string. Using modulo extraction of the needed digits (two) in our case uses %twice and then again twice when converting them to string. Now, if %is the expensive one, I will say point taken, for as long as you need more than two digits from your channel number, knowing that the latter cannot be longer than four. And would be a point on my side if all you need is one digit (or one consecutive block of digits such as %100). But then again, I think we are talking about minimal impact and somewhere at some under layer the two methods are becoming almost same and we will get very similar effort in getting result y from given x. Have a nice one, man!
  • PHSJason wrote: »
    To add another spin, which saves more memory? Having a port on a panel with 2406+ channels being used, or using a string sent from each button with the ASCII characters in it to redirect to the function?
    data_event[vdvModero5]
    {
      string:
        {
        stack_var CHAR cCHANNEL [4]
        cCHANNEL = DATA.TEXT
        call 'send light button push' (1, 6,cCHANNEL)
        }
     }
    


    Anything on this method versus the conversion of the channel to a string?
  • a_riot42a_riot42 Posts: 1,624
    PHSJason wrote: »
    Anything on this method versus the conversion of the channel to a string?

    It would certainly get around the 4000 button limit. Be a pain to create the panel file though.
    Paul
  • DHawthorneDHawthorne Posts: 4,584
    String operations are generally cheaper than math operations in terms of the processor, because most string ops are simply memory operations. You have an array, and you are looking at a portion of it. When you do a math operation you have to read the memory and calculate something. For quick, relatively infrequent tasks, it hardly matters, but if you have a lot going one it's just less work to iterate through memory space than to calculate values.
  • Spire_JeffSpire_Jeff Posts: 1,917
    a_riot42 wrote: »
    define_call 'send light button push' (integer intProc, integer intLink, char sButtonChannel[])
    {
      send_command vHWI,"'K:P:[',itoa(intProc),':',itoa(intLink),':', get_buffer_string(sButtonChannel, 2),']:',sButtonChannel" 
    }
    
    button_event[vdvModero5,0]
    {
      push:
        call 'send light button push' (1, 6, itoa(button.input.channel))
     }
    
    

    Paul

    I don't think this method will work on keypads 1-9 without some sort of math or format command.

    Jeff
Sign In or Register to comment.