Home AMX User Forum AMX General Discussion
Options

REBUILD_EVENT()

Since the discussion a couple of days ago I decided to run some tests cuz R_E is still a little fuzzy. In the main code I use one button event that utilizes defined UIs and the catch all 0 just to verify the push and this event isn't part of the test.
DEFINE_EVENT	//BUTTON_EVENT [vTP_Arry,nTestBtn_Arry]

BUTTON_EVENT [vTP1,0]
BUTTON_EVENT [vTP2,0]
BUTTON_EVENT [vTP3,0]

     {
     PUSH:
	  {
	  STACK_VAR INTEGER nBtn;
	  STACK_VAR INTEGER nUI_Indx;
	  
	  nBtn = BUTTON.INPUT.CHANNEL;
	  nUI_Indx = (BUTTON.INPUT.DEVICE.NUMBER - 33000);
	  
	  SEND_STRING 0, "'FROM MAIN, BIC * UI-[ ',itoa(nUI_Indx),' ] PUSHED BTN-[ ',itoa(nBtn),' ] :DEBUG<',itoa(__LINE__),'>'";
	  }
     }  
then I create another button event that uses the arrays. I also create a module and pass these arrays into the module and then a button event inside the module to use these arrays.
MAIN
BUTTON_EVENT [vTP_Arry,nTestBtn_Arry]

     {
     PUSH:
	  {
	  STACK_VAR INTEGER nBtn;
	  STACK_VAR INTEGER nUI_Indx;
	  
	  nBtn = GET_LAST(nTestBtn_Arry);
	  nUI_Indx = GET_LAST(vTP_Arry);
	  
	  SEND_STRING 0, "'FROM MAIN, GET_LAST * UI-[ ',itoa(nUI_Indx),' ] PUSHED BTN-[ ',itoa(nBtn),' ] :DEBUG<',itoa(__LINE__),'>'";
	  }
     }     

MODULE

DEFINE_EVENT	//BUTTON_EVENT [vTPs,nBtns]

BUTTON_EVENT [vTPs,nBtns]

     {
     PUSH:
	  {
	  STACK_VAR INTEGER nBtn;
	  STACK_VAR INTEGER nUI_Indx;
	  
	  nBtn = GET_LAST(nBtns);
	  nUI_Indx = GET_LAST(vTPs);
	  
	  SEND_STRING 0, "'FROM MODULE, UI-[ ',itoa(nUI_Indx),' ] PUSHED BTN-[ ',itoa(nBtn),' ] :DEBUG<',itoa(__LINE__),'>'";
	  }
     }

if we start with arrays that aren't initialized:
DEFINE_VARIABLE	//ARRAYS AND VARS

VOLATILE INTEGER nTestBtn_Arry[NUM_TEST_BTNS];
VOLATILE DEV vTP_Arry[NUM_TEST_TPS];
then initialize these arrays in define start, then use set_length_array() and then rebuild_events() only the main code will trigger a button event. Nothing from the module!
Line     29 (11:46:13)::  FROM MAIN, BIC * UI-[ 1 ] PUSHED BTN-[ 1 ] :DEBUG<82>
Line     30 (11:46:13)::  FROM MAIN, GET_LAST * UI-[ 1 ] PUSHED BTN-[ 1 ] :DEBUG<99>
So we also have to trigger the RE in the module to get that event table to function.
Line     32 (11:55:46)::  FROM MODULE STARTING REBUILD_EVENTS :DEBUG<32>
Line     33 (11:55:46)::  FROM MODULE, FINSIHED REBUILD_EVENTS :DEBUG<34>
then the same button push yields:
Line     34 (11:56:00)::  FROM MAIN, BIC * UI-[ 1 ] PUSHED BTN-[ 1 ] :DEBUG<82>
Line     35 (11:56:00)::  FROM MAIN, GET_LAST * UI-[ 1 ] PUSHED BTN-[ 1 ] :DEBUG<99>
Line     36 (11:56:00)::  FROM MODULE, UI-[ 1 ] PUSHED BTN-[ 1 ] :DEBUG<20>
if you init the arrays, rebuild the events in both the main and module but don't set the array lengths before calling rebuild_event a button push won't fire an event in the main or module which means the rebuild function uses length_array not max_length_array.

if you init the arrays and set the lengths in the main code but only rebuild_event in the module the module button event will fire but the main's won't.
Line      5 (14:10:25)::  FROM MAIN, BIC * UI-[ 1 ] PUSHED BTN-[ 1 ] :DEBUG<82>
Line      6 (14:10:25)::  FROM MODULE, UI-[ 1 ] PUSHED BTN-[ 1 ] :DEBUG<20>
Remember the MAIN, BIC always fires since it's defined and initialized during compile.

Now if you take that same define_start section and init the arrays, set the lengths but don't rebuild in that section but then create another array and in a different define_start intit the array, set the length but in this code section rebuild the events the event table are re-built for both the old and new array even though the rebuild event was enclosed in braces. The instructions state that only items used in events enclosed in the braces are rebuilt but it appears everything in the main is. The module still won't work until rebuild event is called in the module.

So basically rebuild event isn't limited to scope by braces and seems to rebuild everything in the main which should include, includes. Modules however are out of that scope and will require their own if it's needed.

IMHO if you're using a button array and then just populating it with a loop of sequential numbers then using the array is pointless and you're better off for many reason just using the catch all 0. If you're shifting non sequential channel numbers to index positions then that's a different story. I almost always initialize my UI arrays where defined so there aren't many reasons for needing to initialize arrays in define start and using rebuild event for button array related needs since if you're using non sequential button mapping you have no choice but to manually enter those values.

Testing code for anyone that wants to play:
(testing on an NI-700 running v3.50.430)
Main
PROGRAM_NAME='REBUILD_EVENT_TEST'

DEFINE_DEVICE	//VIRTUAL TPs

vTP1		= 33001:1:0;
vTP2		= 33002:1:0;
vTP3		= 33003:1:0;

DEFINE_CONSTANT	//ARRAY SIZES

NUM_TEST_BTNS	= 20;
NUM_TEST_TPS	= 3;

DEFINE_VARIABLE	//ARRAYS AND VARS

VOLATILE INTEGER nTestBtn_Arry[NUM_TEST_BTNS];
VOLATILE INTEGER nTestBtn_Arry2[NUM_TEST_BTNS];
VOLATILE DEV vTP_Arry[NUM_TEST_TPS];

VOLATILE INTEGER nRunTest = 0;
VOLATILE INTEGER nModTest = 0;

DEFINE_MODULE 'REBUIL_EVENT_MOD' R_E_mod1(vTP_Arry,nTestBtn_Arry,nModTest)

#DEFINE ALLOW_START_ITEMS
#IF_DEFINED ALLOW_START_ITEMS

     #DEFINE ALLOW_SET_LENGTHS
     //#DEFINE ALLOW_REBUILD_EVENT

     DEFINE_START
     
	  {
	  STACK_VAR INTEGER i;
	  
	  for(i = NUM_TEST_BTNS; i; i--)
	       {
	       nTestBtn_Arry[i] = i;
	       }
	  for(i = NUM_TEST_TPS; i; i--)
	       {
	       STACK_VAR INTEGER nDev;
	       
	       nDev = (33000 + i);
	       vTP_Arry[i] = nDev:1:0;
	       }
	  SEND_STRING 0, "'FROM MAIN, INTIALIZED ARRAYS :DEBUG<',itoa(__LINE__),'>'";
	  
	  #IF_DEFINED ALLOW_SET_LENGTHS
	       SET_LENGTH_ARRAY(nTestBtn_Arry,NUM_TEST_BTNS);
	       SET_LENGTH_ARRAY(vTP_Arry,NUM_TEST_TPS);
	       SEND_STRING 0, "'FROM MAIN, SET LENGTH ARRAYS :DEBUG<',itoa(__LINE__),'>'";
	  #ELSE
	       #WARN 'SET LENGTH ARRAY ITEMS EXCLUDED FROM COMPILE'
	  #END_IF
	  
	  #IF_DEFINED ALLOW_REBUILD_EVENT
	       SEND_STRING 0, "'FROM MAIN, STARTING REBUILD_EVENTS :DEBUG<',itoa(__LINE__),'>'";
	       REBUILD_EVENT()
	       SEND_STRING 0, "'FROM MAIN, FINSIHED REBUILD_EVENTS :DEBUG<',itoa(__LINE__),'>'";
	  #ELSE
	       #WARN 'REBUILD_EVENT EXCLUDED FROM COMPILE'
	  #END_IF
	  }
#ELSE
     #WARN 'DEFINE START ITEMS EXCLUDED FROM COMPILE'
#END_IF

DEFINE_START

     {
     STACK_VAR INTEGER i;
	  
     for(i = NUM_TEST_BTNS; i; i--)
	  {
	  nTestBtn_Arry2[i] = (NUM_TEST_BTNS + i);
	  }
     SET_LENGTH_ARRAY(nTestBtn_Arry2,NUM_TEST_BTNS);
     REBUILD_EVENT();
     }

DEFINE_EVENT	//BUTTON_EVENT [vTP_Arry,nTestBtn_Arry]

BUTTON_EVENT [vTP1,0]
BUTTON_EVENT [vTP2,0]
BUTTON_EVENT [vTP3,0]

     {
     PUSH:
	  {
	  STACK_VAR INTEGER nBtn;
	  STACK_VAR INTEGER nUI_Indx;
	  
	  nBtn = BUTTON.INPUT.CHANNEL;
	  nUI_Indx = (BUTTON.INPUT.DEVICE.NUMBER - 33000);
	  
	  SEND_STRING 0, "'FROM MAIN, BIC * UI-[ ',itoa(nUI_Indx),' ] PUSHED BTN-[ ',itoa(nBtn),' ] :DEBUG<',itoa(__LINE__),'>'";
	  }
     }  

DEFINE_EVENT	//BUTTON_EVENT [vTP_Arry,nTestBtn_Arry]

BUTTON_EVENT [vTP_Arry,nTestBtn_Arry]

     {
     PUSH:
	  {
	  STACK_VAR INTEGER nBtn;
	  STACK_VAR INTEGER nUI_Indx;
	  
	  nBtn = GET_LAST(nTestBtn_Arry);
	  nUI_Indx = GET_LAST(vTP_Arry);
	  
	  SEND_STRING 0, "'FROM MAIN, GET_LAST * UI-[ ',itoa(nUI_Indx),' ] PUSHED BTN-[ ',itoa(nBtn),' ] :DEBUG<',itoa(__LINE__),'>'";
	  }
     }

DEFINE_EVENT	//BUTTON_EVENT [vTP_Arry,nTestBtn_Arry]

BUTTON_EVENT [vTP_Arry,nTestBtn_Arry2]

     {
     PUSH:
	  {
	  STACK_VAR INTEGER nBtn;
	  STACK_VAR INTEGER nUI_Indx;
	  
	  nBtn = GET_LAST(nTestBtn_Arry2);
	  nUI_Indx = GET_LAST(vTP_Arry);
	  
	  SEND_STRING 0, "'FROM MAIN, GET_LAST * UI-[ ',itoa(nUI_Indx),' ] PUSHED BTN-[ ',itoa(nBtn),' ] :DEBUG<',itoa(__LINE__),'>'";
	  }
     }          

DEFINE_PROGRAM	//TESTING CODE

if(nRunTest)
     {
     SWITCH(nRunTest)
	  {
	  CASE 1:
	       {
	       SEND_STRING 0, "'FROM MAIN, STARTING REBUILD_EVENTS :DEBUG<',itoa(__LINE__),'>'";
	       REBUILD_EVENT()
	       SEND_STRING 0, "'FROM MAIN, FINSIHED REBUILD_EVENTS :DEBUG<',itoa(__LINE__),'>'";
	       }
	  CASE 2:
	       {
	       STACK_VAR INTEGER i;
	       
	       for(i = NUM_TEST_BTNS; i; i--)
		    {
		    nTestBtn_Arry[i] = i;
		    }
	       }
	  CASE 3:
	       {
	       STACK_VAR INTEGER i;
	       
	       for(i = NUM_TEST_TPS; i; i--)
		    {
		    STACK_VAR INTEGER nDev;
		    
		    nDev = (33000 + i);
		    vTP_Arry[i] = nDev:1:0;
		    }
	       }
	  CASE 4:
	       {
	       vTP_Arry[1] = 33001:1:0;
	       vTP_Arry[2] = 33002:1:0;
	       vTP_Arry[3] = 33003:1:0;
	       }
	  CASE 5:
	       {
	       SET_LENGTH_ARRAY(nTestBtn_Arry,NUM_TEST_BTNS);
	       }
	  CASE 6:
	       {
	       SET_LENGTH_ARRAY(vTP_Arry,NUM_TEST_TPS);
	       }
	  CASE 7:
	       {
	       SET_LENGTH_ARRAY(nTestBtn_Arry,0);
	       }
	  CASE 8:
	       {
	       SET_LENGTH_ARRAY(vTP_Arry,0);
	       }
	  }
     nRunTest = 0;
     }

Module:
MODULE_NAME='REBUIL_EVENT_MOD' (DEV vTPs[],INTEGER nBtns[],INTEGER nModTest)

DEFINE_CONSTANT	//ARRAYS SIZES

NUM_TEST_BTNS	= 20;
NUM_TEST_TPS	= 3;

DEFINE_EVENT	//BUTTON_EVENT [vTPs,nBtns]

BUTTON_EVENT [vTPs,nBtns]

     {
     PUSH:
	  {
	  STACK_VAR INTEGER nBtn;
	  STACK_VAR INTEGER nUI_Indx;
	  
	  nBtn = GET_LAST(nBtns);
	  nUI_Indx = GET_LAST(vTPs);
	  
	  SEND_STRING 0, "'FROM MODULE, UI-[ ',itoa(nUI_Indx),' ] PUSHED BTN-[ ',itoa(nBtn),' ] :DEBUG<',itoa(__LINE__),'>'";
	  }
     }
     
DEFINE_PROGRAM	//TESTING CODE

if(nModTest)
     {
     SWITCH(nModTest)
	  {
	  CASE 1:
	       {
	       SEND_STRING 0, "'FROM MODULE STARTING REBUILD_EVENTS :DEBUG<',itoa(__LINE__),'>'";
	       REBUILD_EVENT()
	       SEND_STRING 0, "'FROM MODULE, FINSIHED REBUILD_EVENTS :DEBUG<',itoa(__LINE__),'>'";
	       }
	  CASE 2:
	       {
	       STACK_VAR INTEGER i;
	       
	       for(i = NUM_TEST_BTNS; i; i--)
		    {
		    nBtns[i] = i;
		    }
	       }
	  CASE 3:
	       {
	       STACK_VAR INTEGER i;
	       
	       for(i = NUM_TEST_TPS; i; i--)
		    {
		    STACK_VAR INTEGER nDev;
		    
		    nDev = (3300 + i);
		    vTPs[i] = nDev:1:0;
		    }
	       }
	  CASE 4:
	       {
	       vTPs[1] = 33001:1:0;
	       vTPs[2] = 33002:1:0;
	       vTPs[3] = 33003:1:0;
	       }
	  CASE 5:
	       {
	       SET_LENGTH_ARRAY(nBtns,NUM_TEST_BTNS);
	       }
	  CASE 6:
	       {
	       SET_LENGTH_ARRAY(vTPs,NUM_TEST_TPS);
	       }
	  CASE 7:
	       {
	       SET_LENGTH_ARRAY(nBtns,0);
	       }
	  CASE 8:
	       {
	       SET_LENGTH_ARRAY(vTPs,0);
	       }
	  }
     nModTest = 0;
     }

Comments

  • Options
    ericmedleyericmedley Posts: 4,177
    Nice work Vinning!
    I kinda went down this same path when I was trying to impliment a dynamic UI but kept running into conceptual paradoxes based upon how I 'thought' it should work and it actually worked. I performed similar test just to prove my own sanity to myself. It was the call to tech support that verified I wasn't nuts.

    To be honest, I just gave up using R_E. it never quite worked as advertised and there are better approaches to getting around it anyway.

    If it did work as advertised, it would sure make it a lot easier to make systems more dynamic and changeable on the fly. But alas and anon...
  • Options
    viningvining Posts: 4,368
    ericmedley wrote: »
    To be honest, I just gave up using R_E. it never quite worked as advertised and there are better approaches to getting around it anyway.
    .
    Totally agree, I personally don't see the need for button arrays at all either unless you're remapping channel numbers to a common index format which I rarely do and if you do you pretty much have to init those values where defined anyway. For me 99.9% of the time I'll use 0 since it catches everything and uses the least amount of resources. I don't use a bunch of little button arrays with their own button events. I'd rather just use one button event with the 0 catch all and then filter pushes, releases, etc through a select active.

    For me the only time I use R_E is when I increase virtual counts so if I increase my virtual level counts from the default 8 to say 24 then I'll plan on using an R_E after a delay. I don't know if that's actually required after increasing virtual counts but it seems like it should be but maybe the set virtual count function already has that built in. I guess to satisfy my own anal curiousity I'll test those today and see if I need R_E at all.
  • Options
    viningvining Posts: 4,368
    Tests using SET_VIRTUAL_COUNTS. (For testing I'm only using level counts)

    Using the previous code I add set level count in define start:
    for(i = NUM_TEST_TPS; i; i--)
    	       {
    	       STACK_VAR INTEGER nDev;
    	       
    	       nDev = (33000 + i);
    	       vTP_Arry[i] = nDev:1:0;
    	       SET_VIRTUAL_LEVEL_COUNT(vTP_Arry[i],NUM_TEST_LVLS);
    	       }
    
    so 1st of all my array isn't init where defined, I also created two level events in my main, one uses the define vTP and the other uses the array which gets init in define start.
    DEFINE_EVENT	//LEVEL_EVENT[vTP1,0]..LEVEL_EVENT[vTP3,0]
    
    LEVEL_EVENT[vTP1,0]
    LEVEL_EVENT[vTP2,0]
    LEVEL_EVENT[vTP3,0]
               
         {
         STACK_VAR INTEGER nLVL;
         STACK_VAR INTEGER nValue;
         STACK_VAR INTEGER nUI_Indx;
    	  
         nLVL = LEVEL.INPUT.LEVEL
         nValue = LEVEL.VALUE;
         nUI_Indx = (LEVEL.SOURCEDEV.NUMBER - 33000);
    	  
         SEND_STRING 0, "'FROM MAIN, LSN * UI-[ ',itoa(nUI_Indx),' ], LVL-[ ',itoa(nLVL),' ], VALUE-[ ',itoa(nValue),' ] :DEBUG<',itoa(__LINE__),'>'";
         }           
    
    DEFINE_EVENT	//LEVEL_EVENT[vTP_Arry,0]
    
    LEVEL_EVENT[vTP_Arry,0]
    
         {
         STACK_VAR INTEGER nLVL;
         STACK_VAR INTEGER nValue;
         STACK_VAR INTEGER nUI_Indx;
    	  
         nLVL = LEVEL.INPUT.LEVEL
         nValue = LEVEL.VALUE;
         nUI_Indx = GET_LAST(vTP_Arry);
    	  
         SEND_STRING 0, "'FROM MAIN, GET_LAST * UI-[ ',itoa(nUI_Indx),' ], LVL-[ ',itoa(nLVL),' ], VALUE-[ ',itoa(nValue),' ] :DEBUG<',itoa(__LINE__),'>'";
         }           
    
    So upon program load I init my virtual array and set my virtual level count per virtual to 24 in define start.
    Uisng emulate device I send level 1 value 40 emulating virteual dev 1.
    Line     23 (09:09:07)::  FROM MAIN, LSN * UI-[ 1 ], LVL-[ 1 ], VALUE-[ 40 ] :DEBUG<160>
    
    and only the level event that uses the vTP1,0..vTP3,0 triggers a level. The event that uses the array doesn't since it had no values when the event tables were built.
    While here I test higher levels and they all seem to work in the event handler that uses vTP1,0..vTP3,0 which immediately tells me I don't need to use R_E just because I used set_virtual_level_count. I've always assume I would so I have been. So what they say about people who assume is true. :)

    Now in this scenario where I init the virtual dev array in define start I would have to use R_E to get those event table to work but again why would anyone really want to init their arrays in define start.

    Anyway so I call R_E in the main and now that event handler that uses the array init in define start triggers and then when I call R_E in the module which also uses the same array it triggers.

    If you decide to run these tests you need to remember to change your level value each time cuz the master won't acknowledge the same level twice so it won't print to diagnostics again if the same level is sent again. I forgot and thought I broke it! :)

    So the moral of the story is you don't need to call R_E because you increased virtual counts but like the button events if arrays that are used in event handlers are init anywhere other than where they're defined (define_variable) you'll need to set their length and rebuild the events. If you're using constant arrays they can only be init in define_constant so that's never an issue.

    Since there's really no point in initializing arrays used in event handlers anywhere other than where they're defined and in most cases using button arrays at all is pointless unless as discussed rebuild event has very limited purpose and typically shouldn't be required. Like I said earlier I thought I needed it when I increased my virtual counts but that doesn't appear to be the case so I'm now I can be R_E free.
  • Options
    ijedijed Posts: 28
    R_E == Religious Experience

    Trying to set level counts on a dynamic array of devices

    Semi-obvious now that I think about it but this:
    MODULE_NAME='Switcher_Enova_DVX_xxx' (DEV vdvSwitcher, DEV dvSwitcher, integer nSwitchStatus[])
    
    DEFINE_VARIABLE
    integer nOutputs = MAX_OUTPUTS
    dev dvOutputs[MAX_OUTPUTS]
    
    
    DEFINE_START
    nOutputs = MAX_LENGTH_ARRAY(nSwitchStatus)
    	
    SET_LENGTH_ARRAY(dvOutputs, nOutputs)
    for(i = 1; i <= nOutputs; i++)
    {
    	dvOutputs[i] = dvSwitcher.NUMBER:i:dvSwitcher.SYSTEM
    	set_virtual_level_count(dvOutputs[i], 255)
    }
    rebuild_event()
    
    

    doesn't work but this:
    DEFINE_START
    nOutputs = MAX_LENGTH_ARRAY(nSwitchStatus[1])
    	
    SET_LENGTH_ARRAY(dvOutputs, nOutputs)
    for(i = 1; i <= nOutputs; i++)
    {
    	dvOutputs[i] = dvSwitcher.NUMBER:i:dvSwitcher.SYSTEM
    }
    rebuild_event()
    		
    for(i = 1; i <= nOutputs; i++)
    {
    	set_virtual_level_count(dvOutputs[i], 255)
    }
    

    does

    So until the device is in the event table you can't increase their levels

    ....

    hallelujah!
  • Options
    Spire_JeffSpire_Jeff Posts: 1,917
    It has been a while since I have tried using this command, so I don't recall exactly what I was trying to do with it. I can tell you that this can be a very dangerous command to use in a large system. Depending on how large your event table is, this command can cause your processor to stop responding for minutes (I was in the 8-10 minutes range) while the event tables are processed. I don't recall if everything would queue up while it was processing, or if everything was ignored, or a combination of both... I just recall it drove me nuts for a few hours :)

    Jeff
  • Options
    a_riot42a_riot42 Posts: 1,624
    After authoring hundreds of systems, I have never used rebuild_event, and never had a reason to. One of the programmers I worked with had it all through their modules, and I removed it with no ill effect. Netlinx is not a dynamically typed language, and trying to force it to be leads to madness imho. I'm quite fond of my hair and want to keep as much of it as possible so I don't do this. I'm guessing tacking Java onto Netlinx was an attempt at implementing a dynamic language over top of Netlinx, but I am still not sure how well that worked out.

    I couldn't use the button event wildcard since I use the hold event with different times, repeats, etc depending on the device. I use the wild card for one event that I want to have happen on every button press on every device, but I use predefined arrays for everything else.
    Paul
  • Options
    tomktomk Posts: 24
    Spire_Jeff wrote: »
    this command can cause your processor to stop responding for minutes (I was in the 8-10 minutes range) while the event tables are processed

    You're not wrong that it's processor-heavy but even on a complicated project I find it only runs for a few seconds. I did get it to lock up by putting it inside a loop that was modifying event tables - by pulling it out and running it once after all the loops it was all fine.
    a_riot42 wrote:
    After authoring hundreds of systems, I have never used rebuild_event, and never had a reason to. One of the programmers I worked with had it all through their modules, and I removed it with no ill effect. Netlinx is not a dynamically typed language, and trying to force it to be leads to madness imho

    I'm not going to let that one slide. :) If you have a fairly complicated module that you need to modify down the line, you have all kinds of places where you can introduce bugs by copy-pasting code incorrectly or forgetting to add new entries to join arrays or device arrays etc. It's completely understandable if you're looking at it 12 months later.

    I recently wrote a NetLinx program to control 10 PDUs - 10 virtual devices, each with 8 ports, each needing to be toggled on and off by a particular button on a touch panel. The configuration and join numbers are likely to change in the future. Do I want lines upon lines of constants? No way.

    Out of 300 lines of code all of the configuration is maintained in:
    - 10 variables containing the IP addresses of the PDUs
    - a series of lines under DEFINE_START:
    // pdu, port, offtime, bootuptime, join
    InitPDUOutlet(dvPDU1, 2, 5, 30, 2090);
    InitPDUOutlet(dvPDU1, 4, 5, 30, 2091);
    InitPDUOutlet(dvPDU1, 6, 5, 30, 2092);
    // ...
    dcOnOffListeners = dcOnOffListeners;
    rebuild_event();
    

    In one little block of code I am defining which outlets on which PDUs are tied to which joins, how many seconds each device needs to be off for before it is turned on again, and how many seconds before it should register as being finished turning on.

    InitPDUOutlet() does a few things:
    - Adds a new pdu outlet structure to the end of an array, containing the settings passed in, so we can use it later
    - Creates a devchan inside that structure for the touch panel button
    - Adds that devchan to the array that we're listening on

    When a button press is detected from the devchan array, it goes through the array of structures to find the one that corresponds to the press. It then has all the parameters and knows what to do with it.

    Luckily I can now forget about all that detail - and if I ever need to change a PDU Outlet I can just change one line and not introduce any bugs! :)

    EDIT: In case anyone is interested in this kind of thing, this is a general programming principle called Don't Repeat Yourself: in short, that if you change one thing you shouldn't have to run around and update other bits of code to reflect that. DRY is really very hard to achieve with NetLinx - much easier with Java - but there are some small things you can do. :)
  • Options
    a_riot42a_riot42 Posts: 1,624
    tomk wrote: »
    I'm not going to let that one slide. :) If you have a fairly complicated module that you need to modify down the line, you have all kinds of places where you can introduce bugs by copy-pasting code incorrectly or forgetting to add new entries to join arrays or device arrays etc. It's completely understandable if you're looking at it 12 months later.

    I think you can achieve the same thing without using r_e. I can see it can be useful in some instances, but being the processor hog it is is a deal breaker for me. I don't use devchans either so perhaps if I did I would be tempted to use it. Adding new entries to arrays is trivial so I guess I don't see the need. What's the point of the line dcOnOffListeners = dcOnOffListeners;? Is that a trick needed to make r_e work?
    Paul
  • Options
    tomktomk Posts: 24
    a_riot42 wrote: »
    I think you can achieve the same thing without using r_e.
    I suspect you're right. You could have a predefined array for all of the joins that might be interesting, or simply do a catchall on channel 0. It just means that you might process some events that aren't registered in the array. In my opinion it's not as neat but you can certainly gain the benefit of clustered config code without REBUILD_EVENT.
    a_riot42 wrote: »
    I can see it can be useful in some instances, but being the processor hog it is is a deal breaker for me.
    I did come across another case where I felt I should use it. If you are creating a virtual device that implements the listbox protocol it has to be able to receive table or view definitions on arbitrary ports. I suppose you could manually define a bunch of DATA_EVENT handlers and say to your user "Okay you have to use ports 1-16 and don't you dare change the virtual port count". The alternative is to add a new device to the DATA_EVENT handler on the fly when a listbox object is registered on that port then run REBUILD_EVENT. I went with the latter since I could.
    a_riot42 wrote: »
    What's the point of the line dcOnOffListeners = dcOnOffListeners;? Is that a trick needed to make r_e work?
    Yes indeed. REBUILD_EVENT only affects variables that have been changed in the same function. If you only change the element of an array (as opposed to assigning a new array to the array variable), any event handlers using that array will not be updated.
  • Options
    viningvining Posts: 4,368
    I though we did some tests a while back and determine the R_E wasn't limited in scope to the braces where it's called like the docs indicate but instead would rebuilt all the event if called anywhere in the main or include and the same occurred in modules so it's really only isolated between individual module and the main. So if R_E is needed in the main in multiple loctions it should only be called once since anywhere it's call will rebuild everything all calling it multiple times is what can really bog down the start up.

    Calling during start up is one thing but during runtime it takes the event handlers offline for x amount of time and the system can't perform any tasks like button pushes or channel triggers.
  • Options
    vining wrote: »
    I though we did some tests a while back and determine the R_E wasn't limited in scope...
    I believe that was post #1 of this thread.

    Also, this thread has a thorough discussion: Button_event and array definition question
  • Options
    a_riot42a_riot42 Posts: 1,624
    tomk wrote: »
    I suspect you're right. You could have a predefined array for all of the joins that might be interesting, or simply do a catchall on channel 0. It just means that you might process some events that aren't registered in the array. In my opinion it's not as neat but you can certainly gain the benefit of clustered config code without REBUILD_EVENT.

    With Netlinx I am less concerned about neat as functional. With an RTOS, my priority is CPU scheduling, since there is no built in scheduler and the CPU will happily run R_E for days if necessary.
    tomk wrote: »
    I did come across another case where I felt I should use it. If you are creating a virtual device that implements the listbox protocol it has to be able to receive table or view definitions on arbitrary ports. I suppose you could manually define a bunch of DATA_EVENT handlers and say to your user "Okay you have to use ports 1-16 and don't you dare change the virtual port count". The alternative is to add a new device to the DATA_EVENT handler on the fly when a listbox object is registered on that port then run REBUILD_EVENT. I went with the latter since I could.

    I think the only time I would use R_E is in define_start. Otherwise it could impact latency in a running system. Just my opinion.
    tomk wrote: »
    Yes indeed. REBUILD_EVENT only affects variables that have been changed in the same function. If you only change the element of an array (as opposed to assigning a new array to the array variable), any event handlers using that array will not be updated.

    Ugh, I thought so. Thanks for the info, although I hope to never have to use it :)
    Paul
  • Options
    champchamp Posts: 261
    An acronym i like is KISS.
    I don't use R_E and prefer defining all button numbers in constant arrays, all button numbers are defined in the same spot so i won't accidentally use a channel twice. In addition i don't need button numbers for each function to be consecutive.
Sign In or Register to comment.