Home AMX User Forum NetLinx Studio

DEVCHAN and COMBINE_CHANNELS

Hello

I would like to request some expertise as far as correctly using the COMBINE_CHANNELS. Thanks for the patience in reviewing the whole introduction.

Particularly, I have a project with a decent number of devices, and I found easier to handle the button events by assigning channel numbers to the buttons in a sequence that makes relevance for the actual device controlled, and, in many cases, using different channel ports so I can start the count over.

For example, when using IR control for a sat receiver, I would define a new TP device, different channel port, let's say 10001:7:0, and assign channel numbers to buttons as they are numbered for the IR device (1 = "Power", 10 = "0",..., 55 = "FFWD",...,169 ="Menu".
Similar, if I have to control some light dimmers, I would assign channels matching the dimmer address for ON, dimmer address + 100 for OFF, and so on....

This way, I would only have to use the following BUTTON_EVENT:
DEFINE_DEVICE 
dvSatTP = 10001.7.0
dvSatIR = 5001:9:0

//----------------
DEFINE_CONSTANT 
SatButtons[] = {1,10,55,169}
//----------------- 

BUTTON_EVENT [dvSatTP, SatButtons]
{
      PUSH:
      {
            PULSE [dvSatIR, BUTTON.INPUT.CHANNEL]
      }
}

Or, in other cases, BUTTON.INPUT.CHANNEL altered with 100, 200 or whatever the functions defined have been numbered on the button.

The whole above logic seemed to have a complete downside when having to integrate with previously programmed TP's, one other RF-one-way VPT-CP. On this one, obviously, I could not afford the luxury of skipping channels as all you have is ONE device with 255 Channels. So, I had to use all the channels (and I would have needed some more), naming the buttons above, let's say, 1 = "Power", 2="0", 3="FFWD", 4="Menu".

Looking at possible ways of "translating" the presses from this panel to a virtual panel of the first type, I came across COMBINE_CHANNELS. And here's where the question arises:

I wrote this
DEFINE_DEVICE
dvRFTP = 131:1:0
dvSatIR = 5001:9:0
dvSatTP = 10001:7:0
vdvSatTP = 33033:1:0
//----------------
DEFINE_CONSTANT 
SatButtons[] = {1,10,55,169}
//-----------------------
DEV TPArray[] = {vdvSatTP, dvSatTP}
//-----------------------
DEVCHAN dcRFButtons [] = {{dvRFTP,1},{dvRFTP,2},{dvRFTP3},{dvRFTP,4}}
DEVCHAN vdcVirtualButtons [] = {{vdvSatTP,1},{vdvSatTP,10},{vdvSatTP,55},{vdvSatTP,169}}
//

DEFINE_START
{
       //-----------------------------
       COMBINE_CHANNELS (vdcVirtualButtons, dcRFButtons)
}

BUTTON_EVENT [dvTPArray, SatButtons]
{
       PUSH:
       {
               PULSE [dvSatIR, BUTTON.INPUT.CHANNEL]
       }
}

My understanding and expectation was that the virtual panel will get the "translated" channel at any press on the actual RF Panel, and, being in the array, will produce the same effect as a press on the dvTP. Well, it did not happen quite so. Quite at all... Moreover, the virtual device did not list any entries in the "Asynchronous Notifications" list, unlike the case when you have the devices themselves combined...

I presume my understanding of the whole paradigm behind COMBINE_CHANNELS has a flaw somewhere, or there is some silly mistake I made.

Please consider the example above an arbitrary one, the real one would have been quite a block of code, and the actual definitions are being spread along several include files. Also, if there is some punctuation or syntax mistake, it's not there. Anything the compiler would pick up. Thanks.

Also, should there be other professional practice recommendation regarding the numbering of the buttons on a touch panel, and such "translations", please use no mercy :-)

Comments

  • TurnipTruckTurnipTruck Posts: 1,485
    I used to use a bunch of COMBINE_CHANNELS, but have since found better ways.

    I have run into similar situations to yours where I have keypads in a system that control more than one aspect of the system. Think of an eight-button keypad in a house where you have audio, lighting and something else on the keypad. You could use the same set of buttons on all keypads for each purpose and end up with some simple code, but in the real world, I find the need to use different buttons on different keypads.

    So I came up with a module I call "Keypad Manager" Keypad manager brings in a dev array of all of the actual keypads and outputs pushes through three virtual devices that correspond to virtual ports and channels that you assign in an array. That way all of the lighting control arrives on a specific virtual device that can be DEV arrayed with touchpanel ports where you have the luxury to use whatever channel numbers you want. You may be able to get this work in your situation.

    The module code below is configured for five sixteen button keypads creating three seperate virtual devices for control.

    It may not be the most efficient thing in operation, but it makes for WAY simpler programming with keypads in a system.
    MODULE_NAME='mdlKeyPadManager_3_00' (DEV vdvKeypadManager,						//Module Virtual Device
    									    DEV vdvKeypads[],							//Array of Virtual Keypads
    									    DEV dKeypads[],								//Array of Actual Keypads
    									    INTEGER nKeypadEnable[],					//Aray of Keypad Enable/Disable
    									    INTEGER nTableInput[][][])   //[5] [16] [2]		//Table of Keypad Assignments
    
    DEFINE_DEVICE
    
    DEFINE_CONSTANT
    VOLATILE INTEGER nTotKPs=5
    VOLATILE INTEGER nTotVKPs=3
    
    DEFINE_TYPE
    
    DEFINE_VARIABLE
    VOLATILE INTEGER nUI
    VOLATILE INTEGER nBut
    VOLATILE INTEGER nLoop
    VOLATILE INTEGER nLoopUI
    VOLATILE INTEGER nLoopBut
    VOLATILE INTEGER nTableOutput[255][nTotKPs][nTotVKPs]
    
    VOLATILE INTEGER nAssignedPort
    VOLATILE INTEGER nAssignedChannel
    
    DEFINE_LATCHING
    
    DEFINE_MUTUALLY_EXCLUSIVE
    
    DEFINE_START
    FOR (nLoopUI=1;nLoopUI<=nTotKPs;nLoopUI++)						//Loop of Each Keypad 1-5
        {
        FOR (nLoopBut=1;nLoopBut<=16;nLoopBut++)						//Loops of each Button of each keypad 1-16
    	{
    	nAssignedPort=nTableInput[nLoopUI][nLoopBut][1]
    	nAssignedChannel=nTableInput[nLoopUI][nLoopBut][2]
    	IF (nAssignedPort>0)
    	    {
    	    nTableOutput[nAssignedChannel][nLoopUI][nAssignedPort]=nLoopBut
    	    }
    	}
        }
    
    DEFINE_EVENT
    BUTTON_EVENT [dKeypads,0]
    {
    PUSH:
        {
        nUI=GET_LAST (dKeypads)
        IF (nKeypadEnable[nUI])
    	{
    	nBut=BUTTON.INPUT.CHANNEL
    	IF (nTableInput[nUI][nBut][1]>0)		//There is an virtual keypad button assogned to this real button
    	    {
    	    DO_PUSH_TIMED (vdvKeypads[nTableInput[nUI][nBut][1]], nTableInput[nUI][nBut][2],DO_PUSH_TIMED_INFINITE)
    	    }
    	}
        }
    RELEASE:
        {
        nUI=GET_LAST (dKeypads)
        IF (nKeypadEnable[nUI])
    	{    
    	nBut=BUTTON.INPUT.CHANNEL
    	IF (nTableInput[nUI][nBut][1]>0)		//There is an virtual keypad button assogned to this real button
    	    {
    	    DO_RELEASE (vdvKeypads[nTableInput[nUI][nBut][1]], nTableInput[nUI][nBut][2])
    	    }
    	}
        }    
    }
    
    CHANNEL_EVENT [vdvKeypads,0]
    {
    ON:
        {
        nUI=GET_LAST (vdvKeypads)
        nBut=CHANNEL.CHANNEL
        FOR (nLoop=1;nLoop<=nTotKPs;nLoop++)
    	{
    	IF (nTableOutput[nBut][nLoop][nUI]>0)
    	    ON [dKeypads[nLoop],nTableOutput[nBut][nLoop][nUI]]
    	}
        }
    OFF:
        {
        nUI=GET_LAST (vdvKeypads)
        nBut=CHANNEL.CHANNEL
        FOR (nLoop=1;nLoop<=nTotKPs;nLoop++)
    	{
    	IF (nTableOutput[nBut][nLoop][nUI]>0)
    	    OFF [dKeypads[nLoop],nTableOutput[nBut][nLoop][nUI]]
    	}
        }    
    }
    
    DEFINE_PROGRAM
    

    Below is the variable definition to go in the main program
    DEFINE_VARIABLE//----------------------------------------------------------------------------------------------------------------------------------------KEYPAD MANAGER
    //SET NUMBER OF KEYPADSs and VIRTUAL KEYPADS in MODULE IN DEFINE_CONSTANT
    DEV dKeypads[nTotKPs]={dvKeypad01,dvKeypad02,dvKeypad03,dvKeypad04,dvKeypad05}
    PERSISTENT INTEGER nKeypadEnable[nTotKPs]
    DEV vdKeypads[nTotVKPs]={vdvKeyPads01_Audio,vdvKeyPads02_Lighting,vdvKeyPads03}
    
    //Assignment Ports:
    //1=Audio
    //2=Lighting
    VOLATILE INTEGER nKeypadAssignmentTable[nTotKPs][16][2]=
    {
    {{0,0},{0,0},{0,0},{0,0},{1,231},{1,241},{0,0},{0,0},{0,0},{0,0},{0,0},{1,201},{1,211},{0,0},{0,0},{0,0}},
    {{0,0},{0,0},{0,0},{0,0},{1,234},{1,244},{0,0},{0,0},{0,0},{0,0},{0,0},{1,204},{1,214},{0,0},{0,0},{0,0}},
    {{2,203},{2,204},{2,201},{2,202},{1,237},{1,247},{0,0},{0,0},{0,0},{0,0},{0,0},{1,207},{1,217},{0,0},{0,0},{0,0}},
    {{2,208},{2,209},{2,206},{2,207},{1,238},{1,248},{0,0},{0,0},{0,0},{0,0},{0,0},{1,208},{1,218},{0,0},{0,0},{0,0}},
    {{2,213},{2,214},{2,211},{2,212},{1,239},{1,249},{0,0},{0,0},{0,0},{0,0},{0,0},{1,209},{1,219},{0,0},{0,0},{0,0}}
    }
    

    And here is the module definition
    DEFINE_MODULE'mdlKeyPadManager_3_00' KPMGR01		(vdvKeypadManager01,						//Module Virtual Device
    													vdKeypads,								//Array of Virtual Keypads
    													dKeypads,								//Array of Actual Keypads
    													nKeypadEnable,							//Array of Keypad Enable/Disbale
    													nKeypadAssignmentTable)   //[5] [16] [2]		//Table of Keypad Assignments
    
  • That's more or less what I ended up doing... Well, almost and very particularized to my case, not left open for future implementations as yours.
    DEFINE_CONSTANT 
    RFBloodyButtons [] = {1,2,3,4}
    SatButtons [] = {1,10,55,169}
    
    /////----------------
    BUTTON_EVENT [dvRFTP, RFBloodyButtons]
    {
           PUSH:
           {
                    DO_PUSH (vdvSatTP, SatButtons[ GET_LAST(RFBloodyButtons)])
           }
    }
    

    I will have a thorough look at your work as my show would not be either complete without two keypads... :)

    But, still, my question is raised by the failure of understanding and correctly implementing a purpose built solution such as COMBINE_CHANNELS. I would imagine this is more ore less the reason of such a facility, "pairing" different channels on different devices and making them performing the same end action.
  • TurnipTruckTurnipTruck Posts: 1,485
    But, still, my question is raised by the failure of understanding and correctly implementing a purpose built solution such as COMBINE_CHANNELS. I would imagine this is more ore less the reason of such a facility, "pairing" different channels on different devices and making them performing the same end action.

    You are correct. The purpose is to take a range of DEVCHANS and combine them into one DEVCHAN.
    COMBINE_CHANNELS(vDevchan,Devchan)
    

    Above, Devchan is an array of DEVCHANs that that you want to respond together. vDevchan is the DEVCHAN that you would refer to in your code to get events from the combined DEVCHANs.
  • Thanks Dave. It appears that I understood correctly the paradigm, yet, I am probably doing some silly mistake while implementing it.
    I think I will drop it for now and go my "other" way, since the client will never know or care which is the chosen method. And, eventually, it will strike me, and will be clearer than the daylight....
Sign In or Register to comment.