Home AMX User Forum NetLinx Studio

Button Event for all channels?

Currently I'm doing something like this...
integer keypad_buttons[] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,etc...}

BUTTON_EVENT[someDevice,keypad_buttons]
{
    PUSH:
    {
	SEND_STRING someOtherDevice, "'button ',itoa(button.input.channel)"
    }
}   

Firrst of all is there a shorthand way to do this instead of having to define the huge array? I was thinking just "BUTTON_EVENT[someDevice]" but that doesn't work...

Secondly, and not so important, I was unable to get 'button.input.channel' to return any value, and I was having to assign it first to a variable, I'd rather not have to assign it to a variable, is there a way to use it within an expression string like shown above, or should it work the way illustrated and maybe something else in my code is causing problems? Perhaps having other button_events defined for same device cause problems?

Thanks

Comments

  • BUTTON_EVENT[somedevice,0] will give you every button push on that device. Usefull with G4 touchpanels where you can use different port assignments.
  • Please post code

    button.input.channel works fine for me.

    Could you post a compilable program that illustrates the problem?
  • DHawthorneDHawthorne Posts: 4,584
    I've never liked using the "wildcard" button channel. It seems to me it is too easy to get unexpected results, so I always limit my event table to distinct channel groups. I break them up by function (source selection, transport controls, numeric buttons, etc.) so they don't get too large (there is an upper limit for the size of an event table - 2048 element, was it? or 1024?). But what I wind up with is exactly like your example. I just don't really see a problem with it. The sequential numbering tool makes it easy to populate such arrays.
  • ericmedleyericmedley Posts: 4,177
    DHawthorne wrote:
    I've never liked using the "wildcard" button channel. It seems to me it is too easy to get unexpected results...QUOTE]


    Ture dat,

    I too find the whole 'I only have one button event in my whole program' thing a little silly. You still at some point have to make a distinction of which button(s) are hit and what you wish to do when that button gets hit. You end up with a very small button event command but a large wild goose chase to figure out what the button actually does.

    While lowering the number of button_events does lower the number of program lines, I'm not sure it actually lowers the number of program elements.

    I tend to use all three methods depending upon the circumstance. I still use 'somewhat' large button_event stacks when there's a lot of math happening after the event. It's easier for me to keep track of the thought process to me.

    However for IR controls or seriously large Lutron button event stacks I'll go to the [some_device,big_button_array]

    Someday, perhaps we'll have the magic "One button command does my whole program!" :)
  • Youn wrote:
    Currently I'm doing something like this...
    integer keypad_buttons[] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,etc...}
    
    BUTTON_EVENT[someDevice,keypad_buttons]
    {
        PUSH:
        {
    	SEND_STRING someOtherDevice, "'button ',itoa(button.input.channel)"
        }
    }   
    

    Firrst of all is there a shorthand way to do this instead of having to define the huge array? I was thinking just "BUTTON_EVENT[someDevice]" but that doesn't work...

    Secondly, and not so important, I was unable to get 'button.input.channel' to return any value, and I was having to assign it first to a variable, I'd rather not have to assign it to a variable, is there a way to use it within an expression string like shown above, or should it work the way illustrated and maybe something else in my code is causing problems? Perhaps having other button_events defined for same device cause problems?

    Thanks
    There is no short cut to the the array of button channels and it is one of the most effective ways of writing your program.

    'button.input.channel' will never return anything outside the button_event because it becomes nul as soon as the event is over. Your send_string should work fine within the button_event.

    Try using nSomeVarialbe = Get_Last(keypad_buttons) to return the index of the array keypad_buttons. This can very valuable as a pointer to other arrays.
  • alexanboalexanbo Posts: 282
    The place I find useful to use the [device,0] wildcard is actually for channel events. Before the NI-900 came out we'd often sell an NI-700 that controlled a couple pieces of gear via IR. You'd then be forced to stack the IR onto one IR port so that for example the Sat IR would be 1-50 and the dvd would be 51-100.

    I'd then create a virtual device to represent the dvd and write something like:

    Channel_Event[vdvDVD,0]
    {
    On:
    {
    Send_command dvIR,"'SP',channel.channel. + 50"
    }
    }

    And then I could treat the virtual device exactly like a real IR device in my IR routing code.
  • ericmedleyericmedley Posts: 4,177
    B_Clements wrote:
    ...'button.input.channel' will never return anything outside the button_event because it becomes nul as soon as the event is over.

    An easy way to get around that is store the button.input.channel
    In fact, I do it with all the paramerters as a matter of course.

    DEV dev_TP_Master_1[ ] = // this links all the touch panels together
    {dvTP_1_Library, // info to all.
    dvTP_1_Masterbed,
    dvTP_1_Kitchen,
    dvTP_1_Garage,
    dvTP_1_Den,
    dvTP_1_Ground
    }


    Button_Event[dev_TP_Master_1,big_ole_button_array]
    {
    push:
    {
    TP_DEVICE=Button.Input.Device.Number
    TP_PORT=Button.Input.Device.Port
    TP_SYSTEM=Button.Input.Device.System
    TP_BUTTON_PUSHED=BUTTON.INPUT.CHANNEL
    TO[TP_DEVICE:TP_PORT:TP_SYSTEM,TP_BUTTON_PUSHED] // feedback to button on TP

    etc...


    that's how I like to do it...
  • Joe HebertJoe Hebert Posts: 2,159
    Youn wrote:
    Firrst of all is there a shorthand way to do this instead of having to define the huge array?

    I?m not sure how much of a shortcut this is especially considering the sequential numbering tool but you do have the option to create a variable array and plug in your numbers with a loop.

    For example let?s say you have 200 lights and want a button for each and you want the first light button to start at 101. Consider the following:
    DEFINE_DEVICE
    
    dvTP	= 10001:1:0
    
    DEFINE_CONSTANT
    
    INTEGER nMaxLights	= 200
    INTEGER nLightsOffset	= 100
    
    DEFINE_VARIABLE
    
    INTEGER nLightButtons[nMaxLights]
    
    DEFINE_FUNCTION fnInitLights () {
    
       INTEGER x
       
       FOR(x=1; x<=nMaxLights; x++) {
          nLightButtons[x] = x + nLightsOffset
       }
    
       SET_LENGTH_ARRAY(nLightButtons,nMaxLights)   
       REBUILD_EVENT() //update the event table
       
    }
    
    DEFINE_START
    
    fnInitLights()
    
    DEFINE_EVENT
    
    BUTTON_EVENT[dvTP,nLightButtons] {
    
       PUSH: {
          //do whatever
       }
    }
    
  • Just make sure you add the REBUILD_EVENT(), to register the button events effected in DEFINE_START, or in the function itself
    Joe Hebert wrote:
    I?m not sure how much of a shortcut this is especially considering the sequential numbering tool but you do have the option to create a variable array and plug in your numbers with a loop.

    For example let?s say you have 200 lights and want a button for each and you want the first light button to start at 101. Consider the following:
    DEFINE_DEVICE
    
    dvTP	= 10001:1:0
    
    DEFINE_CONSTANT
    
    INTEGER nMaxLights	= 200
    INTEGER nLightsOffset	= 100
    
    DEFINE_VARIABLE
    
    INTEGER nLightButtons[nMaxLights]
    
    DEFINE_FUNCTION fnInitLights () {
    
       INTEGER x
       
       FOR(x=1; x<=nMaxLights; x++) {
          nLightButtons[x] = x + nLightsOffset
       }
    
       SET_LENGTH_ARRAY(nLightButtons,nMaxLights)   
       REBUILD_EVENT() //update the event table
       
    }
    
    DEFINE_START
    
    fnInitLights()
    
    DEFINE_EVENT
    
    BUTTON_EVENT[dvTP,nLightButtons] {
    
       PUSH: {
          //do whatever
       }
    }
    
  • icraigie wrote:
    Just make sure you add the REBUILD_EVENT(), to register the button events effected in DEFINE_START, or in the function itself

    It looks like it is in the function from the code example given.

    Great idea, Joe.
  • jjamesjjames Posts: 2,908
    Learn something new everyday! I didn't know you could use a variable in a BUTTON_EVENT definition (i.e. BUTTON_EVENT[dvTP,nLightButtons]). That may come in handy. For all of my TV channel macros, I put them on a seperate port from the main channels (i.e. dvTP_CAB = 10001:02:00) and do this:
    BUTTON_EVENT[dvTP_CAB,BUTTON.INPUT.CHANNEL]
    {
       PUSH:
          fnSEND_STATION(dvCAB1,BUTTON.INPUT.CHANNEL)
    }
    
    .. and that will take care of all of my TV macros - of course the button channel would be assigned in the TP file and a function would be present to send the IR to cable box.

    Monitoring all pushes for a timeout function or whatnot, I use BUTTON_EVENT[dvTP,0] - which I believe was suggested by Joe in a somewhat related thread.
  • DHawthorneDHawthorne Posts: 4,584
    jjames wrote:
    Learn something new everyday! I didn't know you could use a variable in a BUTTON_EVENT definition (i.e. BUTTON_EVENT[dvTP,nLightButtons]). That may come in handy. For all of my TV channel macros, I put them on a seperate port from the main channels (i.e. dvTP_CAB = 10001:02:00) and do this:
    BUTTON_EVENT[dvTP_CAB,BUTTON.INPUT.CHANNEL]
    {
       PUSH:
          fnSEND_STATION(dvCAB1,BUTTON.INPUT.CHANNEL)
    }
    
    .. and that will take care of all of my TV macros - of course the button channel would be assigned in the TP file and a function would be present to send the IR to cable box.

    Monitoring all pushes for a timeout function or whatnot, I use BUTTON_EVENT[dvTP,0] - which I believe was suggested by Joe in a somewhat related thread.
    No, that won't work as written. BUTTON.INPUT.CHANNEL is not determined until the event actually happens, and event tables are created on startup. Any event in that block will never happen. Button events with a variable as a parameter only work if that variable has a value when the the program starts, or if the event table is rebuilt when the variable is populated or changed. If BUTTON.INPUT.CHANNEL even has meaning outside that code block (I don't know if it retains the last value), even rebuilding it then would result in the last value defining the event, not the value it has in the actual event. So you can't use it inside the event definition, unless by sheer coincidence they match. Typically, variables used in the definition are initialized, so they exist when the program starts.
  • jjamesjjames Posts: 2,908
    DHawthorne wrote:
    No, that won't work as written. BUTTON.INPUT.CHANNEL is not determined until the event actually happens, and event tables are created on startup. Any event in that block will never happen.

    Well then . . . I guess it's just sheer luck that it works absolutely perfect on all of my jobs that I've done. Out of pure curiosity - have you tried it, or are you going off of your vast knowledge of the NetLinx Programming Language? Since you posted so quickly after my suggestion, I'll guess you didn't even test it.

    Like they say . . . don't knock it until you try it. Trust me, it works.

    I'll be posting code later.
  • mpullinmpullin Posts: 949
    jjames wrote:
    BUTTON_EVENT[dvTP_CAB,BUTTON.INPUT.CHANNEL]
    I have not tested it but it looks very suspicious. I'll agree with Dave in that it is not sound programming. BUTTON.INPUT.CHANNEL is supposed to refer to a property of an event that hasn't happened yet. I'll be curious to see your application and learn why it works (if it does).
  • alexanboalexanbo Posts: 282
    Just a hypothesis without seeing the actual code but unless the rebuild_event call is used, when the event is added to the event table button.input.channel = 0 so the event is built as [dvTP_CAB,0] which means any button event on that port will fire the code and hence why it works.
  • dchristodchristo Posts: 177
    It works because BUTTON.INPUT.CHANNEL resolves to 0 at compile-time, so the event effectively captures all presses from that port. It does not, however, work the same as it did in Axcess, i.e., PUSH[Device,PUSH_CHANNEL]

    --D
  • jjamesjjames Posts: 2,908
    Well - I never truely knew why it worked, only knew it did. So essentially [dvTP,BUTTON.INPUT.CHANNEL] = [dvTP,0] which is I assume the "accepted" way of doing a "button event for all channels".

    I guess it's all about pragmatics.
  • DHawthorneDHawthorne Posts: 4,584
    jjames wrote:
    Well then . . . I guess it's just sheer luck that it works absolutely perfect on all of my jobs that I've done. Out of pure curiosity - have you tried it, or are you going off of your vast knowledge of the NetLinx Programming Language? Since you posted so quickly after my suggestion, I'll guess you didn't even test it.

    Like they say . . . don't knock it until you try it. Trust me, it works.

    I'll be posting code later.
    No need to get snide. I didn't mean it to be high-handed. I generally check in on these forums while I'm between other things, and don't always get the chance to make a test run. In this case, I misread what you posted, and thought you were suggesting a course of action, not stating that you have actually done it and that it worked. I thought I was giving you a heads up that might save you some grief. I didn't even consider that it's resolving to 0 would create a defacto wildcard, I just knew that it was invalid in that context.
  • jjamesjjames Posts: 2,908
    DHawthorne wrote:
    No need to get snide.
    True, my apologies. I'm often a bit too quick to snap back and reply on something that I know works, not to mention it usually comes out a bit sharp.
    DHawthorne wrote:
    In this case, I misread what you posted, and thought you were suggesting a course of action, not stating that you have actually done it and that it worked.
    Understood - I misread often as well. I just thought I was clear in the way that I suggested it by saying it is what I do for my TV macros.

    No hard feelings, right? Not trying to make an excuse, but I'm occasionaly rough on the edges before lunch, but I'm really not that bad of a guy - really! :D Perhaps I should stay off the forums before I feed my appetite for the BK Big Fish.
  • DHawthorneDHawthorne Posts: 4,584
    jjames wrote:
    True, my apologies. I'm often a bit too quick to snap back and reply on something that I know works, not to mention it usually comes out a bit sharp.


    Understood - I misread often as well. I just thought I was clear in the way that I suggested it by saying it is what I do for my TV macros.

    No hard feelings, right? Not trying to make an excuse, but I'm occasionaly rough on the edges before lunch, but I'm really not that bad of a guy - really! :D Perhaps I should stay off the forums before I feed my appetite for the BK Big Fish.
    No hard feelings. I confess I was a little hurt - but I also tend to shoot off replies after a quick scan of a message rather than after a careful reading. So I have to take some responsibility myself. I was honestly just trying to be helpful, and I am as much chagrined that I wasn't completely right in my response as having made the wrong impression with you.
Sign In or Register to comment.