Home AMX User Forum AMX General Discussion

Least amount of code writing for IR command button presses?

I have a project with 6 sat receivers, 3 blu ray players, and 4 cable boxes. Since the IR codes are set up in a standardized fashion, I was looking for a way to easily send these codes without writing button events for every button on every device. I have started to create a button array:
VOLATILE INTEGER nBtnArray[] = //Button Array for all IR device presses
     {	
     1,
     2,
     3,
     4,
     5,
And I was going to use this array with a get_last to then direct what code was being sent:
BUTTON_EVENT[dvTPMB_BluRay,nBtnArray]  //Blu Ray button group
{
    PUSH:
    {
	PULSE[BLURAY,GET_LAST(nBtnArray)]
    }
}
I don't have access to an NI currently, but will this work? I think I'm missing something. I've defined the touchpanel with a level for each device:
IE, 10001:2:0 is the Sat DVR, 10001:3:0 is the Blu Ray, and so on. This way I would only have to create a button event for each level on the touchpanel(with copy and paste), and then be done with my IR code button events. Or, at least, that's my thought. I'm also wondering if I need to declare every button number like I did above - it's just that I'm trying to avoid typing out/declaring all 255 button numbers in the array.

Comments

  • ericmedleyericmedley Posts: 4,177
    One thing I might suggest to add is another array that deals with how each button number relates to each IR channel. It is certainly possible to have the button numbers lineup with the IR channels, but it gets a little ugly later on down the line when, for example, the bluRay player changes remotes and the customer wants to switch it out. Now, not only are you changing IR codes, but your working in TP design too.

    How I do this myself is make the array for the IR channels. then I copy and paste the same array below and make the IR channels comments for the button numbers I'm doing. Now make the Button Array in this copied section and rename the array to buttons or whatever.

    In essense you've created a data table that relates your buttons to your IR channels.

    So later if you have to change out some buttons or change the layout, it's much easier.

    Just a suggestion.
  • DHawthorneDHawthorne Posts: 4,584
    Yes, you have to declare every button number, or it won't be part of the event table that triggers the PUSH handler. But do you really need all 255 buttons? I have yet to see an IR file that used that many channels. Whatever the number though, just cut and paste however many lines you need, then use the "Sequentially Number Selection" button. It's one of the handiest NS editor features available.

    I would strongly recommend you don't use PULSE on the IR device either, it's on a global timer and is difficult to tweak per device; using the SP command will let you also use CTON and CTOF to adjust the timing.
  • ColzieColzie Posts: 470
    DHawthorne wrote: »
    Yes, you have to declare every button number, or it won't be part of the event table that triggers the PUSH handler

    Not exactly true.
    define_event[dv_TP, 0]
    {
        push:
        {
            //  every dv_TP button can be handled here
        }
    }
    
  • ColzieColzie Posts: 470
    To add a bit more, I use a standard layout for all of my IR devices.

    Every IR file follows the same layout of play, stop, pause, etc.

    Every TP file has the button's channel number matched to the IR file.

    Then using the above code I can capture everything and pass to the proper IR device.

    When the customer switches out the DVD to a Bluray all I have to do is make sure the new Bluray IR is set up properly, and add any necessary buttons to the TP file.
  • ColzieColzie Posts: 470
    Also, if you use the same port in the TP file for your Bluray and Cable pages, you can track which source the TP is controlling (i_tp_source below), and issue the IR command to the proper device. This eliminates a section of code for each device -- one define_event captures it for all of them.
    define_device
    dv_CABLE1_IR = 5001:01:00
    dv_CABLE2_IR = 5001:02:00
    dv_BLURAY1_IR = 5001:03:00
    dv_BLURAY2_IR = 5001:04:00
    
    dv_TP_IR = 10001:02:00  //  TP port 2 for all IR devices
    
    define_variable
    dv_IR_Devices[] = {dv_CABLE1_IR, dv_CABLE2_IR, dv_BLURAY1_IR, dv_BLURAY2}
    
    define_event
    button_event [dv_TP_IR, 0]
    {
        push:
        {
            if (button.input.channel)  //  make sure this isn't zero
            {
                //  i_tp_source set elsewhere; 1=dv_CABLE1_IR, 2=dv_CABLE2_IR, etc.
                to[dv_IR_Devices[i_tp_source], button.input.channel]
            }
        }
    }
    
  • the8thstthe8thst Posts: 470
    There is another way to handle this with less code. Like the previously mentioned methods it does have it's positives and negatives.

    Use a variable to track which source is currently selected and assign the channel numbers on the touch panel to directly correspond to the IR channel (you can have them be different for each source just by using different panel pages), then use 1 button event for all devices.
    define_event
    button_event[dvSourceControlTPs,0]
    {
          push: {
                stack_var integer nTPindex
    
                nTPindex = get_last(dvSourceControlTPs)
                send_command dvSources[nCurrentSource[nTPIndex],"'SP',button.input.channel"
          }
    }
    

    Something like that would handle all of your IR (0 is a wildcard for any channel, so make sure to only use that port for source IR control).


    edit: I guess there were a number of responses since my phone rang.....
  • HedbergHedberg Posts: 671
    So, you have 10 IR devices which you can combine into an array of devices. For each of the 10 IR devices you can set up a TP port (10 TP ports) and combine those 10 TPs into one device array. Then you can have exactly one button_event to handle the whole thing -- determine which device to pulse (or whatever, if you don't want to use pulse) by which TP port triggered the event. Your TP ports can be ordered in the manner of the IR devices and you can use get_last on the TP device array or you can just perform arithmetic on the port number. Like this:
    button_event[vdvTP_Array,nBtnNmbrs]
    {
      push:
      {
         nBtnIndx = get_last(nBtnNmbrs)
         nTPIndx = get_last(vdvTP_Array)
         pulse[vdvIRDeviceArray[nTPIndx],nIRChanArray[nBtnIndx]]
       }
    }
    
  • chillchill Posts: 186
    I do IR devices similarly to what vegastech posted, except I'll use an array of buttons and an array of IR channels:
    volatile integer dvd_buttons[] =
    {
      701,  // play
      702,  // stop
      703,  // menu
      .
      .
    }
    
    volatile integer dvd_ir[] =
    {
      1,  // play
      2,  // stop
     45,  // menu
      .
      .
    }
    
    button_event[dvd_buttons,dvd_ir]
    {
      push :
      {
        to[button.input]
        to[dvd,dvd_ir[get_last(dvd_buttons)]]
      }
    }
    

    If there are multiple panels or dvd players, either or both of those things can be an array. For multiple decks, I use a separate set of buttons for the user to choose which deck to control, or maybe it happens transparently. In that case, dvd is an array.

    And there is no need to declare all 255 buttons/functions - just do the ones you think you might need. I generally allocate 20 buttons for each type of machine, which leaves me a few spares. Since you're doing sat, blu-ray and cable, you'd end up with three sets of button/IR integer arrays (assuming all the blu-rays, etc. are the same model). Even with 20 members each, that's a lot less heinous.

    Also - notice I used TO, not PULSE, to activate the IR function. DHawthorne is correct.
    .
  • Ok, I got a little confused here. So much to read...(In a good way!)
    I'm going to start out small and work my way up, so please bear with me.
    I define each level of the TP I want to control, with a level for each IR device, with #1 being reserved for functions, macros, etc.:
    DEFINE_DEVICE
    //Touchpanels
    dvTPMBed		        = 10001:8:0  //MBed MVP8400
    dvTPMB_BluRay		= 10001:1:0  //MBed TP Blu Ray functions
    dvTPMB_DVR		= 10001:2:0  //MBed TP DVR functions
    dvTPMB_Sat2		= 10001:3:0  //MBed TP Sat2 functions
    dvTPMB_Sat3		= 10001:4:0  //MBed TP Sat3 functions
    dvTPMB_Sat4		= 10001:5:0  //MBed TP Sat4 functions
    dvTPMB_Sat5		= 10001:6:0  //MBed TP Sat5 functions
    
    Now I can create a device array to contain all of the TP's levels:
    DEV arrTPMB[] = {  //hoping to use get_last here eventually
    		    dvTPMB_BluRay,dvTPMB_DVR,
    		    dvTPMB_Sat2,dvTPMB_Sat3,dvTPMB_Sat4,
    		    dvTPMB_Sat5,dvTPMBed
    		}
    


    Then I create an array to store all declared button numbers:
    non_volatile integer nBtnArray[] = {
    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,29,30,31,32,33,34,35,36,37,38,
    39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55
    }
    
    Now I can create the button event to send the IR codes:
    BUTTON_EVENT[arrTPMB,nBtnArray]
    {
        PUSH:
        {
    	local_var integer btn  //last selected button # from TP
    	local_var integer src  //last selected source based on the TP button LEVEL selection
    	btn = get_last(nBtnArray)
    	src = get_last(arrTPMB)
    	TO[src,get_last(nBtnArray)]
        }
    }
    
    It seems to work, in that I can press and hold the satellite buttons and see my iR indicator light up. But setting the TP itself to level 8 seems iffy - I mean, I want to leave room for the always-arriving-late device that no one mentioned, so I kind of need some space here. I added a 'adbeep' to the online event of my TP, but I didn't hear it sound after the last upload...I suppose I could add a +1 to the src variable. Am I overlooking something blatantly obvious that would eventually crash my system? Not only that, but with different devices like sat and blu ray, the button #s do not line up evenly, with things like DVR, List, etc. What can I do about that?
  • Jorde_VJorde_V Posts: 393
    vegastech wrote: »
    Ok, I got a little confused here. So much to read...(In a good way!)
    I'm going to start out small and work my way up, so please bear with me.
    I define each level of the TP I want to control, with a level for each IR device, with #1 being reserved for functions, macros, etc.:
    DEFINE_DEVICE
    //Touchpanels
    dvTPMBed		        = 10001:8:0  //MBed MVP8400
    dvTPMB_BluRay		= 10001:1:0  //MBed TP Blu Ray functions
    dvTPMB_DVR		= 10001:2:0  //MBed TP DVR functions
    dvTPMB_Sat2		= 10001:3:0  //MBed TP Sat2 functions
    dvTPMB_Sat3		= 10001:4:0  //MBed TP Sat3 functions
    dvTPMB_Sat4		= 10001:5:0  //MBed TP Sat4 functions
    dvTPMB_Sat5		= 10001:6:0  //MBed TP Sat5 functions
    
    Now I can create a device array to contain all of the TP's levels:
    DEV arrTPMB[] = {  //hoping to use get_last here eventually
    		    dvTPMB_BluRay,dvTPMB_DVR,
    		    dvTPMB_Sat2,dvTPMB_Sat3,dvTPMB_Sat4,
    		    dvTPMB_Sat5,dvTPMBed
    		}
    


    Then I create an array to store all declared button numbers:
    non_volatile integer nBtnArray[] = {
    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,29,30,31,32,33,34,35,36,37,38,
    39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55
    }
    
    Now I can create the button event to send the IR codes:
    BUTTON_EVENT[arrTPMB,nBtnArray]
    {
        PUSH:
        {
    	local_var integer btn  //last selected button # from TP
    	local_var integer src  //last selected source based on the TP button LEVEL selection
    	btn = get_last(nBtnArray)
    	src = get_last(arrTPMB)
    	TO[src,get_last(nBtnArray)]
        }
    }
    
    It seems to work, in that I can press and hold the satellite buttons and see my iR indicator light up. But setting the TP itself to level 8 seems iffy - I mean, I want to leave room for the always-arriving-late device that no one mentioned, so I kind of need some space here. I added a 'adbeep' to the online event of my TP, but I didn't hear it sound after the last upload...I suppose I could add a +1 to the src variable. Am I overlooking something blatantly obvious that would eventually crash my system? Not only that, but with different devices like sat and blu ray, the button #s do not line up evenly, with things like DVR, List, etc. What can I do about that?

    Your code is either incomplete or you're showing only a portion of it. As for your question, look at chill's solution he shows you how to do just that. With your tp-array you can just add another tp port to it, because in the array you can specify what you want and leave out what you want.
  • I didn't purposely leave any code out - what am I missing, other than the online event for the TP? Now I'm worried that I forgot something elementary!
  • DHawthorneDHawthorne Posts: 4,584
    Colzie wrote: »
    Not exactly true.
    define_event[dv_TP, 0]
    {
        push:
        {
            //  every dv_TP button can be handled here
        }
    }
    

    In a sense, you have declared every button, because 0 is the shortcut for all possible buttons. However, I consider this bad practice, because you could wind up with inadvertent action taking place from a button you forgot about, or was introduced by a panel change in a module you didn't create, etc. I would much rather limit my event tables with the buttons I am actually using.
  • ColzieColzie Posts: 470
    I agree that define_event[dv_TP, 0] creates an opportunity for errors in sloppy systems. However, if you specify one TP port for all of your IR devices, and do the TP-channel-to-IR-file pass-through, it is the fastest way to achieve the OP's goal: "Least amount of code writing for IR command button presses".
  • ericmedleyericmedley Posts: 4,177
    I wonder what the machine code looks like for button_event[dvTP,0]

    Does this essential make the equivalent of a ginormous button stack of
    button_event[dvTP,1]
    button_event[dvTP,2]
    button_event[dvTP,3]
    etc....
    button_event[dvTP,3997]
    button_event[dvTP,3998]
    button_event[dvTP,3999]
    {
      push: {
                // do something for Pete's sake 
               }
    }
    

    If that is the case, then it doesn't seem like it actually ends up being an efficient way to code. (especially since there is a limit to how many events can be in a stack.)
  • viningvining Posts: 4,368
    The "catch all" is apparently easier on the system then one might think?
    http://www.amxforums.com/showthread.php?5943-EVENT-TABLES&highlight=Catch
  • a_riot42a_riot42 Posts: 1,624
    vining wrote: »
    The "catch all" is apparently easier on the system then one might think?
    http://www.amxforums.com/showthread.php?5943-EVENT-TABLES&highlight=Catch

    Easier on the system maybe. Having only one event may be easier on the system but I can't see how it would be easier on the programmer, and ultimately that's more important.
    Paul
  • ColzieColzie Posts: 470
    I guess I'm taking the title of the thread too seriously.

    To me if someone wants to program anything in a concise manner, then there has to be a willingness to understand more than just hard-coding button presses - which would be the "easiest" to understand.

    Thanks vining for pointing me to the other thread. It is good to know that it isn't taxing on the system.
  • ColzieColzie Posts: 470
    Here is a slightly more complete version of how I'd do it...this one compiles so it must work!
    define_device
    dv_SAT1_IR	= 05001:01:00
    dv_SAT2_IR	= 05001:02:00
    dv_SAT3_IR	= 05001:03:00
    dv_SAT4_IR	= 05001:04:00
    dv_SAT5_IR	= 05001:05:00
    dv_SAT6_IR	= 05001:06:00
    
    dv_CABLE1_IR	= 05001:01:02	//  or wherever the additional IR ports are located
    dv_CABLE2_IR	= 05001:02:02
    dv_CABLE3_IR	= 05001:03:02
    dv_CABLE4_IR	= 05001:04:02
    dv_BLURAY1_IR	= 05001:05:02
    dv_BLURAY2_IR	= 05001:06:02
    dv_BLURAY3_IR	= 05001:07:02
    
    dv_TP1		= 10001:01:00  //  TP1 port 1 for GUI control
    dv_TP1_IR	= 10001:02:00  //  TP1 port 2 for all IR devices
    
    dv_TP2		= 10002:01:00  //  TP2 port 1 for GUI control
    dv_TP2_IR	= 10002:02:00  //  TP2 port 2 for all IR devices
    
    
    define_constant
    integer SOURCE_BTNS[] = {101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113}
    
    
    define_variable
    persistent	integer	i_tp_src[2]	//  to track each TP's current source
    volatile	dev	dv_TPs[]	= {dv_TP1, dv_TP2}
    volatile	dev	dv_TPs_IR[]	= {dv_TP1_IR, dv_TP2_IR}
    volatile	dev	dv_SRCs_IR[]	= {dv_SAT1_IR, dv_SAT2_IR, dv_SAT3_IR, dv_SAT4_IR, dv_SAT5_IR, dv_SAT6_IR, 
    						dv_CABLE1_IR, dv_CABLE2_IR, dv_CABLE3_IR, dv_CABLE4_IR, 
    						dv_BLURAY1_IR, dv_BLURAY2_IR, dv_BLURAY3_IR}
    
    
    define_event
    
    //  source selection
    button_event [dv_TPs, SOURCE_BTNS]
    {
    	push:
    	{
    		i_tp_src[get_last (dv_TPs)] = get_last (SOURCE_BTNS)
    	}
    }
    
    
    //  source control
    button_event [dv_TPs_IR, 0]
    {
    	push:
    	{
    		to[dv_SRCs_IR[i_tp_src[get_last (dv_TPs_IR)]], button.input.channel]
    	}
    }
    
    

    Then just make sure your TP buttons for source control are set up on port 2, and that the channel numbers line up with the IR command you want to send out.

    You only need one popup page for each type of source...show the same Sat page whenever any Sat is selected, the same Cable page when any Cable is selected, etc. i_tp_src[x] determines what to do with the button press. Creating a source page for each Sat box (each on a different TP port) is NOT an efficient way to do it.

    Don't get confused that you will have 3 Play buttons (Sat, Cable, and Bluray) that are all on the same port with the same channel number! The code knows what to do!
  • the8thstthe8thst Posts: 470
    Colzie wrote: »
    Here is a slightly more complete version of how I'd do it...this one compiles so it must work!
    define_device
    dv_SAT1_IR	= 05001:01:00
    dv_SAT2_IR	= 05001:02:00
    dv_SAT3_IR	= 05001:03:00
    dv_SAT4_IR	= 05001:04:00
    dv_SAT5_IR	= 05001:05:00
    dv_SAT6_IR	= 05001:06:00
    
    dv_CABLE1_IR	= 05001:01:02	//  or wherever the additional IR ports are located
    dv_CABLE2_IR	= 05001:02:02
    dv_CABLE3_IR	= 05001:03:02
    dv_CABLE4_IR	= 05001:04:02
    dv_BLURAY1_IR	= 05001:05:02
    dv_BLURAY2_IR	= 05001:06:02
    dv_BLURAY3_IR	= 05001:07:02
    
    dv_TP1		= 10001:01:00  //  TP1 port 1 for GUI control
    dv_TP1_IR	= 10001:02:00  //  TP1 port 2 for all IR devices
    
    dv_TP2		= 10002:01:00  //  TP2 port 1 for GUI control
    dv_TP2_IR	= 10002:02:00  //  TP2 port 2 for all IR devices
    
    
    define_constant
    integer SOURCE_BTNS[] = {101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113}
    
    
    define_variable
    persistent	integer	i_tp_src[2]	//  to track each TP's current source
    volatile	dev	dv_TPs[]	= {dv_TP1, dv_TP2}
    volatile	dev	dv_TPs_IR[]	= {dv_TP1_IR, dv_TP2_IR}
    volatile	dev	dv_SRCs_IR[]	= {dv_SAT1_IR, dv_SAT2_IR, dv_SAT3_IR, dv_SAT4_IR, dv_SAT5_IR, dv_SAT6_IR, 
    						dv_CABLE1_IR, dv_CABLE2_IR, dv_CABLE3_IR, dv_CABLE4_IR, 
    						dv_BLURAY1_IR, dv_BLURAY2_IR, dv_BLURAY3_IR}
    
    
    define_event
    
    //  source selection
    button_event [dv_TPs, SOURCE_BTNS]
    {
    	push:
    	{
    		i_tp_src[get_last (dv_TPs)] = get_last (SOURCE_BTNS)
    	}
    }
    
    
    //  source control
    button_event [dv_TPs_IR, 0]
    {
    	push:
    	{
    		to[dv_SRCs_IR[i_tp_src[get_last (dv_TPs_IR)]], button.input.channel]
    	}
    }
    
    

    Then just make sure your TP buttons for source control are set up on port 2, and that the channel numbers line up with the IR command you want to send out.

    You only need one popup page for each type of source...show the same Sat page whenever any Sat is selected, the same Cable page when any Cable is selected, etc. i_tp_src[x] determines what to do with the button press. Creating a source page for each Sat box (each on a different TP port) is NOT an efficient way to do it.

    Don't get confused that you will have 3 Play buttons (Sat, Cable, and Bluray) that are all on the same port with the same channel number! The code knows what to do!

    The other thing to make sure of is that all the touch panels are in the same order in all of your arrays so get_last always points to the correct panel.

    I code all of my IR (and 1-way 232) this way. I track currently select source per touch panel in a structure that also tracks which page the panel is on, which audio outputs it's controlling, which video output is selected, etc.

    Then I use 1 button event for all IR and presets. A simple conditional separates IR codes from presets.

    ~~~ The following is for Paul ~~~~

    The best part about this setup for me is that I can have an installer swap out cable boxes, bluray players, cd changers etc without them needing to touch programming. They know how to load an IR file and how to edit button text and button channels in the TPD4 file.

    I am the only AMX programmer in the company, so it is a huge help for me to be hands off on simple equipment upgrades like this.
  • DHawthorneDHawthorne Posts: 4,584
    ericmedley wrote: »
    I wonder what the machine code looks like for button_event[dvTP,0]

    Does this essential make the equivalent of a ginormous button stack of
    button_event[dvTP,1]
    button_event[dvTP,2]
    button_event[dvTP,3]
    etc....
    button_event[dvTP,3997]
    button_event[dvTP,3998]
    button_event[dvTP,3999]
    {
      push: {
                // do something for Pete's sake 
               }
    }
    

    If that is the case, then it doesn't seem like it actually ends up being an efficient way to code. (especially since there is a limit to how many events can be in a stack.)

    It couldn't possibly be, for exactly the reason you mention. There has to be some run-time handling of the wildcard, which meshes with what Vining says about it being easier on the master. No table lookup involved.
Sign In or Register to comment.