Home AMX User Forum NetLinx Studio

REBUILD_EVENT in modules

I would like to use one module for several devices but unable to catch events
which compiler does not know during compiling process.
It works fine for constants like [dvTP,200] but not for variables and for some reason REBUILD_EVENT doesn't do what it should.

Here is a simple example.
PROGRAM_NAME='test'
DEFINE_DEVICE
    dvTP1 = 10001:1:0
    dvTP2 = 10002:1:0 

DEFINE_MODULE 'Panel' TP1 (dvTP1)
DEFINE_MODULE 'Panel' TP2 (dvTP2)

DEFINE_PROGRAM
DEFINE_START
MODULE_NAME='Panel' (DEV dvTP)
DEFINE_VARIABLE
    DEVCHAN dcBtnDimmer[3];
    DEVCHAN dcBtnRelay[2];

DEFINE_START
    dcBtnDimmer[1]={dvTP,1};dcBtnDimmer[2]={dvTP,2};dcBtnDimmer[3]={dvTP,3};
    dcBtnRelay[1]={dvTP,101};dcBtnRelay[2]={dvTP,102};
    REBUILD_EVENT();
    
DEFINE_EVENT
    BUTTON_EVENT [dcBtnDimmer]
    {	PUSH:
	{   SEND_STRING 0, "'Panel:',itoa(dvTP.Number),', Dimmer:',GET_LAST(dcBtnDimmer)"
	}
    }
    BUTTON_EVENT [dcBtnRelay]
    {	PUSH:
	{   SEND_STRING 0, "'Panel:',itoa(dvTP.Number),', Relay:',GET_LAST(dcBtnRelay)"
	}
    }
    BUTTON_EVENT [dvTP,200]
    {	PUSH:
	{   SEND_STRING 0, "'Panel:',itoa(dvTP.Number),', Button:',itoa(Button.Input.CHANNEL)"
	}
    }

What is wrong?
Thanks!

Comments

  • Aleksey wrote: »
    I would like to use one module for several devices but unable to catch events
    which compiler does not know during compiling process.
    It works fine for constants like [dvTP,200] but not for variables and for some reason REBUILD_EVENT doesn't do what it should.

    Here is a simple example.
    PROGRAM_NAME='test'
    DEFINE_DEVICE
        dvTP1 = 10001:1:0
        dvTP2 = 10002:1:0 
    
    DEFINE_MODULE 'Panel' TP1 (dvTP1)
    DEFINE_MODULE 'Panel' TP2 (dvTP2)
    
    DEFINE_PROGRAM
    DEFINE_START
    
    MODULE_NAME='Panel' (DEV dvTP)
    DEFINE_VARIABLE
        DEVCHAN dcBtnDimmer[3];
        DEVCHAN dcBtnRelay[2];
    
    DEFINE_START
        dcBtnDimmer[1]={dvTP,1};dcBtnDimmer[2]={dvTP,2};dcBtnDimmer[3]={dvTP,3};
        dcBtnRelay[1]={dvTP,101};dcBtnRelay[2]={dvTP,102};
        REBUILD_EVENT();
        
    DEFINE_EVENT
        BUTTON_EVENT [dcBtnDimmer]
        {	PUSH:
    	{   SEND_STRING 0, "'Panel:',itoa(dvTP.Number),', Dimmer:',GET_LAST(dcBtnDimmer)"
    	}
        }
        BUTTON_EVENT [dcBtnRelay]
        {	PUSH:
    	{   SEND_STRING 0, "'Panel:',itoa(dvTP.Number),', Relay:',GET_LAST(dcBtnRelay)"
    	}
        }
        BUTTON_EVENT [dvTP,200]
        {	PUSH:
    	{   SEND_STRING 0, "'Panel:',itoa(dvTP.Number),', Button:',itoa(Button.Input.CHANNEL)"
    	}
        }
    

    What is wrong?
    Thanks!


    Hi

    When I write modules I pass in a TP list(dev array) and have an integer array for my button list - then use GET_LAST to determine which button and which panel triggered the event. This always works - Never used a dev chan array passed in. I just got into a habit of doing it this way and it works.
    There seems to be an issue though when you do this with levels - level.input.level seems to get a bit confused, but thats out of the scope of this.
    I think if you use dev arrays and integer arrays instead, that'll fix your problem

    Duncan
  • viningvining Posts: 4,368
    Do you plan on changing these during runtime? If not just define your arrays normally but if you do plan on dynamically changing these devchan vars what you're doing looks like it should work but i've never used devchans so I've never tried this with them. I can't imagine why it wouldn't work, maybe try some braces to enclose the itmes to rebuild.
  • AlekseyAleksey Posts: 22
    vining wrote: »
    Do you plan on changing these during runtime? If not just define your arrays ...

    It is not possible to define those DEVCHAN arrays as a constant because it refers to a module's parameter which is a variable.
  • AlekseyAleksey Posts: 22
    Hi

    When I write modules I pass in a TP list(dev array) and have an integer array for my button list - then use GET_LAST to determine which button and which panel triggered the event. This always works - Never used a dev chan array passed in. I just got into a habit of doing it this way and it works.
    There seems to be an issue though when you do this with levels - level.input.level seems to get a bit confused, but thats out of the scope of this.
    I think if you use dev arrays and integer arrays instead, that'll fix your problem

    Duncan

    I agree with you and it is good way to use integer arrays for button list.
    But how do you find index of pressed button in integer array if they have nonsequential numbers?
    With DEVHAN and GET_LAST it is easy to get index of button in array.

    And what could be wrong with levels?
  • viningvining Posts: 4,368
    Aleksey wrote: »
    It is not possible to define those DEVCHAN arrays as a constant because it refers to a module's parameter which is a variable.

    You can pass a variable and constant array to a module as a parameter. You can't pass a constant but you can pass a constant array or even an element of a constant array. You can initialize your variable array where it is defined and then not need to initialize it in define start and then rebuild the event tables. The only time you really need to use rebuild event is when you can't initialize your vars used in event table prior to the event tables being built or if you're changing the event table values during runtime.
  • I found that when you populate device arrays dynamically inside a module that adding level_event[device_array] seems to be needed for rebuild_event() to work. At least it does when the d:p:s values are parameterized into module command strings and the devices are not intialized in define_device on that master.
  • AlekseyAleksey Posts: 22
    vining wrote: »
    You can pass a variable and constant array to a module as a parameter....
    This is exactly what I tried to avoid. I need to hide button list in the module. Now I start to think it is not right way for NetLinx.
  • viningvining Posts: 4,368
    Aleksey wrote: »
    This is exactly what I tried to avoid. I need to hide button list in the module. Now I start to think it is not right way for NetLinx.
    You can always define your buttons in the module and then just pass in your devs. You never want to define your devs in a module, usually it's best to do that in just one place but the button var array can be defined anywhere you want, inside or outside the module. It's more normal to do it outside and pass them in but if you're doing this for some security reason then just define them in the module and be done and then you don't need to worry about rebuilding the event tables.
  • truetrue Posts: 307
    Aleksey, just a tip - you're going down a really bad path. As others have said, devchans aren't the way to go for this. But having a weird panel module like this isn't right either.

    But I'll show you a way to fix this with your code just to give you some ideas.
    MODULE_NAME='Panel' (dev tp)
    
    DEFINE_VARIABLE
    
    DEFINE_START
        
    DEFINE_EVENT
    button_event[tp, 0] {
        push: {
            select {
                active (button.input.channel < 100): {
                    SEND_STRING 0, "'Panel:', itoa(button.input.device.number), ', Dimmer: ', itoa(button.input.channel)"
                }
                active (button.input.channel >= 101 && button.input.channel <= 102): {
                    SEND_STRING 0, "'Panel:', itoa(button.input.device.number), ', Relay: ', itoa(button.input.channel - 100)"
                }
                active (button.input.channel == 200): {
                    SEND_STRING 0, "'Panel:', itoa(button.input.device.number), ', Button: ', itoa(button.input.channel)"
                }
                active (true): {
                    SEND_STRING 0, "'Panel:', itoa(button.input.device.number), ', Unhandled: ', itoa(button.input.channel)"
                }
    	}
        }
    }
    

    I've split the lines to make them easier to read in the forum codeblock depending on your screen width.

    Feel free to reply if you don't understand any part of the code.
    Aleksey wrote:
    But how do you find index of pressed button in integer array if they have nonsequential numbers?
    For the purposes of touchpanel interaction and design, why would you need this? One typically cares about the button itself, not its index in an array. (Almost all of my button_events look something like above; you can see I don't even have an array from which to derive indices!)

    You're free (within limits) to use the channels you want, just parse what you need in code depending on what you are doing.
  • AlekseyAleksey Posts: 22
    true, I just wanted to make code easier and more compact.
    In your example you have to subtract (number of first button minus 1) from button's channel. Just compare conditions

    yours: active (button.input.channel >= 101 && button.input.channel <= 102):
    mine: BUTTON_EVENT [dcBtnRelay]

    and relay's number

    yours: "'Panel:', itoa(button.input.device.number), ', Relay: ', itoa(button.input.channel - 100)"
    mine: "'Panel:',itoa(dvTP.Number),', Relay:',GET_LAST(dcBtnRelay)"

    But you and other advisers are definitely right, DEVCHAN isn't good for real code.
    Thanks for help!
  • truetrue Posts: 307
    Aleksey wrote: »
    true, I just wanted to make code easier and more compact.
    In your example you have to subtract (number of first button minus 1) from button's channel. Just compare conditions

    yours: active (button.input.channel >= 101 && button.input.channel <= 102):
    mine: BUTTON_EVENT [dcBtnRelay]

    and relay's number

    yours: "'Panel:', itoa(button.input.device.number), ', Relay: ', itoa(button.input.channel - 100)"
    mine: "'Panel:',itoa(dvTP.Number),', Relay:',GET_LAST(dcBtnRelay)"

    But you and other advisers are definitely right, DEVCHAN isn't good for real code.
    Thanks for help!

    Typically I wouldn't handle it in this way; it was a literal transformation of your code. If you have a ton of stuff, making a stack_var called 'btn', do btn = button.input.channel, can shorten names.

    What I might have for one-off buttons like these would be a switch instead. But it's still quite readable. This is just an example of a way to get this done.

    Where this excels is in, say, handling IR commands for buttons, source or page selectors, etc. where there is a group of buttons that all perform the same/similar action but the relative button number decides what happens.

    And keep in mind, you did miss out that there isn't any of this:
    DEFINE_VARIABLE
        DEVCHAN dcBtnDimmer[3];
        DEVCHAN dcBtnRelay[2];
    
    DEFINE_START
        dcBtnDimmer[1]={dvTP,1};dcBtnDimmer[2]={dvTP,2};dcBtnDimmer[3]={dvTP,3};
        dcBtnRelay[1]={dvTP,101};dcBtnRelay[2]={dvTP,102};
        REBUILD_EVENT();
    

    Lots of ways to get it done, but any way without devchans is best. Good luck =)
  • tomktomk Posts: 24
    I was just having an almost identical problem except using an array of DEV instead of DEVCHAN. The fix is ridiculous but I bet it would work for you too.
    DEFINE_START
    
    set_virtual_port_count(vd, 5);
    
    vdPort1 = vd.number:1:1; // rebuild_event() updates handlers for these DEVs fine
    vdPort2 = vd.number:2:1;
    vdPort3 = vd.number:3:1;
    vdPort4 = vd.number:4:1;
    vdPort5 = vd.number:5:1;
    
    vdPorts[1] = vdPort1; // handler for vdPorts is not updated! Unless...
    vdPorts[2] = vdPort2;
    vdPorts[3] = vdPort3;
    vdPorts[4] = vdPort4;
    vdPorts[5] = vdPort5;
    
    vdPorts = vdPorts; // you add this. Really.
    // (Apparently changing elements does not count as a "modified variable" to rebuild_event() )
    
    rebuild_event();
    
  • truetrue Posts: 307
    tomk wrote: »
    I was just having an almost identical problem except using an array of DEV instead of DEVCHAN. The fix is ridiculous but I bet it would work for you too.

    Interesting - whenever I did REBUILD_EVENT with an array I just used all of the elements in the event handler, didn't even think to try this. VERY helpful information, good work finding it.
  • moty66moty66 Posts: 31
    tomk wrote: »
    // (Apparently changing elements does not count as a "modified variable" to rebuild_event() )
    rebuild_event();
    


    Thanks for sharing, just lost lot of hours trying to fix this issue
  • a_riot42a_riot42 Posts: 1,624
    I don't use devchans, but isn't the problem more of array length? If you add send_string 0, "'Length of array is ', length_array(dcBtnDimmer)" at the end of define_start what is the output?
    Paul
  • GregGGregG Posts: 251
    Aleksey wrote: »
    I agree with you and it is good way to use integer arrays for button list.
    But how do you find index of pressed button in integer array if they have nonsequential numbers?
    With DEVHAN and GET_LAST it is easy to get index of button in array.

    Get_Last works with Integer arrays also:
    PROGRAM_NAME='main.axs'
    DEFINE_DEVICE
    dvTp1 = 10001:1:0
    dvTp2 = 10002:1:0
    dvTp3 = 10003:1:0
    
    dvDVR = 5001:9:0
    
    DEFINE_CONSTANT
    
    Dev dvaTPs[] = { dvTp1, dvTp2, dvTp3 }
    
    Integer nTransportButtons[] =
      101, // Play
      167, // Pause
      872 // Record
    }
    
    Integer nTransportIRFunctions[] =
      1,  // Play
      3,  // Pause
      8   // Record
    }
    
    DEFINE_MODULE 'ir_sender_module' IR1( dvDVR, dvaTps, nTransportButtons, nTransportIRFunctions )
    
    MODULE_NAME='ir_sender_module' ( Dev dvDVR, Dev dvaTps[],
                                                           Integer nTransportButtons[],
                                                           Integer nTransportIRFunctions[] )
    
    DEFINE_EVENT
    
    Button_Event[dvaTps,nTransportButtons]
    {
       Push:
       {
       Stack_Var nWhichPanel, nWhichButton
          nWhichPanel = Get_Last(dvaTps)  // Not need for this example
          nWhichButton = Get_Last(nTransportButtons)
          To[dvDVR, nTransportIRFunctions[nWhichButton]]
    }
    
Sign In or Register to comment.