Home AMX User Forum NetLinx Studio
Options

Managing Feedback - Lighting System

Thankfully, AMX has just released the updated version of the Vantage Infusion module. This module now allows for Feedback based on button LED state. The command string will come in as (KEYPADSYSTEMBUTTONSTATUS-<address>,<status>) So for button with VID 233, it would report as KEYPADSYSTEMBUTTONSTATUS-233,ON if the button was on. Very straightforward. I have implemented the original module numerous times and it works fine. Now, my only question is with regards to the feedback. What would be the easiest way to manage the feedback. If create a new port on my TP for the lighting system, and then assign the button channels and addresses to match the VID #'s, will that automatically pass it through? If not, do I need to monitor a data event and do a find string for KEYPADSYSTEMBUTTONSTATUS? How would you guru's make this work? Keep in mind, that I'm only through Programmer I, so passing things into arrays, structures is still beyond me unless I can get some sample code. With the vantage Qlink System, I did a data event and based on data.text I would send a an on/off state to the button channel.
example:
data_event[vVANTAGE]
{
    string:
    {
        nVANTAGE_FEEDBACK = DATA.TEXT
	IF (data.text == 'K:L:[1:68]:5:1')//liv room
        {
            ON [dvTP_VANTAGE, 101]
        }
	IF (data.text == 'K:L:[1:68]:5:0')
        {
            OFF [dvTP_VANTAGE, 101]
        }
	IF (data.text == 'K:L:[1:67]:5:1')//kitchen
        {
            ON [dvTP_VANTAGE, 102]
        }
	IF (data.text == 'K:L:[1:67]:5:0')
        {
            OFF [dvTP_VANTAGE, 102]
        }
	if (data.text == 'K:L:[1:68]:2:1')//kitchen dim
        {
            ON [dvTP_VANTAGE, 103]
        }
	IF (data.text == 'K:L:[1:68]:2:0')
        {
            OFF [dvTP_VANTAGE, 103]
        }
	IF (data.text == 'K:L:[1:65]:3:1')//master bedroom
        {
            ON [dvTP_VANTAGE, 104]
        }
	IF (data.text == 'K:L:[1:65]:3:0')
        {
            OFF [dvTP_VANTAGE, 104]
        }
	IF (data.text == 'K:L:[1:66]:6:1')//master bedroom DIM
        {
            ON [dvTP_VANTAGE, 105]
        }
	IF (data.text == 'K:L:[1:66]:6:0')
        {
            OFF [dvTP_VANTAGE, 105]
        }
	IF (data.text == 'K:L:[1:68]:6:1')//OFFICE NURSERY
        {
            ON [dvTP_VANTAGE, 106]
        }
	IF (data.text == 'K:L:[1:68]:6:0')
        {
            OFF [dvTP_VANTAGE, 106]
        }
	IF (data.text == 'K:L:[1:67]:2:1')//OFFICE NURSERY DIM
        {
            ON [dvTP_VANTAGE, 107]
        }
	IF (data.text == 'K:L:[1:67]:2:0')
        {
            OFF [dvTP_VANTAGE, 107]
        }
	IF (data.text == 'K:L:[1:67]:3:1')//OFFICE NURSERY LAMP
        {
            ON [dvTP_VANTAGE, 108]
        }
	IF (data.text == 'K:L:[1:67]:3:0')
        {
            OFF [dvTP_VANTAGE, 108]
        }
	IF (data.text == 'K:L:[1:68]:3:1')//CHINA HUTCH
        {
            ON [dvTP_VANTAGE, 109]
        }
	IF (data.text == 'K:L:[1:68]:3:0')
        {
            OFF [dvTP_VANTAGE, 109]
        }
	IF (data.text == 'K:L:[1:66]:5:1')//GARAGE
        {
            ON [dvTP_VANTAGE, 110]
        }
	IF (data.text == 'K:L:[1:66]:5:0')
        {
            OFF [dvTP_VANTAGE, 110]
        }
	IF (data.text == 'K:L:[1:65]:7:1')//GOODBYE
        {
            ON [dvTP_VANTAGE, 112]
        }
	IF (data.text == 'K:L:[1:65]:7:0')
        {
            OFF [dvTP_VANTAGE, 112]
        }
    }
}


This was easy with a small system, but I don't want to have a multitude of If statements in a data_event to do this on a larger system.
Thanks for any help?

Comments

  • Options
    jjamesjjames Posts: 2,908
    Depending on how large the system is, you could create an array of addresses & channel numbers, then compare the DATA.TEXT with a FOR loop. If the address is found in the DATA.TEXT, begin parsing it and turn the channel on or off and then use the loop counter to point at the channel number on the TP.
  • Options
    Spire_JeffSpire_Jeff Posts: 1,917
    Here is a quick sample, but you will still need to tie feedback to the buttons manually. There are many ways to accomplish this, but this should work. You could also adjust the nID if you know that you will only ever care about ID 61-68, you could just subtract 60 from the ID everywhere and reduce the memory required for the array. You could also move the declarations from the define_start section into an Online event on a virtual device to prevent flooding the processor with requests on boot.
    define_type
    STRUCTURE _sLightLink{
    	integer nID
    	integer nButton
    }
    define_variable
    integer nLightFB[nMaxID][nMaxButtons]
    _sLightLink uLightLink[nMaxLightButtons]
    
    define_function fnUpdateLightFeedback(){
    	stack_var integer x;
    	for(x = nMaxLightButtons;x;x--){
    		[dvTP_Vantage,100+x] = nLightFB[uLightLink[x].nID][uLightLink[x].nButton];
    	}
    }
    define_start
    uLightLink[1].nID = 68;
    uLightLink[1].nButton = 5;
    
    uLightLink[2].nID = 67;
    uLightLink[2].nButton = 5;
    
    uLightLink[3].nID = 68;
    uLightLink[3].nButton = 2;
    
    uLightLink[4].nID = 65;
    uLightLink[4].nButton = 3;
    
    uLightLink[5].nID = 66;
    uLightLink[5].nButton = 6;
    
    //Add the rest of them
    
    define_event
    data_event[vVANTAGE]{
        string:{
            nVANTAGE_FEEDBACK = DATA.TEXT;
    		stack_var integer nID;
    		stack_var integer nButton;
    		
    		IF (find_string(data.text, 'K:L:[1:',1)){
    			remove_string(data.text, 'K:L:[1:',1);
    			nId = atoi(data.text);
    			remove_string(data.text, ']:',1);
    			nButton = atoi(data.text);
    			nLightFB[nID][nButton] = atoi(data.text);
    			wait 10
    				fnUpdateLightFeedback();
    		}
    	}
    }
    
    

    Hope this helps,
    Jeff
  • Options
    jjamesjjames Posts: 2,908
    I was thinking of something along those lines as well, but if the IDs jump around (61-68, 82, 84, 90-93, etc), a mathematical approach might not work, hence the array of the addresses he might need.

    He could of course just have an array of the maximum lighting channel numbers defined even if he doesn't use them all (i.e. nLIGHTING_BTNS[] = {101 - 201} and still approach it mathematically (which I would actually probably do), this way if the client decides to add more lights, there's no coding that needs to be changed, but just a TP change.

    I'm starting to do this more and more (define much more than needed) in the event of adding another cable box, DVD, iPod, etc. to choose from and it's worked nicely so far. Many ways to skin a cat. :D
  • Options
    alexsquaredalexsquared Posts: 166
    Thanks for the info guys. The VID's do jump all over the place as you noted could happen.
  • Options
    kbeattyAMXkbeattyAMX Posts: 358
    Here's a way to do it.And it's very scalable.
    data_event[vVantage]
    {
      string:
      {
        if (find_string(data.text,'K:L:[1:',1))
    	{
    	  trash = remove_string(data.text,'K:L:[1:',1)
    	  keypad = atoI(remove_string(data.text,':',1))
    	  buttonpressed = atoI(remove_string(data.text,':',1))
    	  VKeypad[keypad][buttonpressed] = itoa(data.text)
    	}
    	[dvVantage,101] = VKeypad[68][5]
    	[dvVantage,102] = VKeypad[67][5]
    	[dvVantage,103] = VKeypad[68][2]
    	[dvVantage,104] = VKeypad[65][3]
    	[dvVantage,105] = VKeypad[66][6]
    	[dvVantage,106] = VKeypad[68][6]
    	[dvVantage,107] = VKeypad[67][2]
    	[dvVantage,108] = VKeypad[67][3]
    	[dvVantage,109] = VKeypad[68][3]
    	[dvVantage,110] = VKeypad[66][5]
    	[dvVantage,112] = VKeypad[65][7]
      }           
    }
    
    
  • Options
    kbeattyAMXkbeattyAMX Posts: 358
    Sorry Jeff. I didn't see your solution...
  • Options
    alexsquaredalexsquared Posts: 166
    Thanks all for the help. I guess I should've been clear that the code block I attached was how I had done it with the previous system (the qlink version system). For the new system (infusion), looking at Kbeatty's example, could it work using something like this:
    data_event[vVantage]
    {
      string:
      {
        if (find_string(data.text,'KEYPADSYSTEMBUTTONSTATUS-',1))
    	{
    	  trash = remove_string(data.text,'KEYPADSYSTEMBUTTONSTATUS-',1)//IN THE EXAMPLE I MENTION IN THE ORIGINAL POST, I SHOULD ONLY HAVE 233,ON NOW
    	  VKeypad = (data.text)
    	}
    	[dvVantage,101] = VKeypad[233,ON]
    	[dvVantage,102] = VKeypad[234,ON]
    	[dvVantage,103] = VKeypad[235,ON]
    	[dvVantage,104] = VKeypad[236,ON]
    	[dvVantage,105] = VKeypad[237,ON]
    	[dvVantage,106] = VKeypad[238,ON]
    	[dvVantage,107] = VKeypad[239,ON]
    	[dvVantage,108] = VKeypad[240,ON]
      }           
    }
    

    If so, when the button is pushed off and the code comes through as saying 233,OFF, will it automatically change the sate of the button, or do I need to do If statements setting the channel on if I get an on response and off if I get an off response? This is ultimately the step I would like to condense in code instead of having two if commands for every button.
  • Options
    kbeattyAMXkbeattyAMX Posts: 358
    Thanks all for the help. I guess I should've been clear that the code block I attached was how I had done it with the previous system (the qlink version system). For the new system (infusion), looking at Kbeatty's example, could it work using something like this:
    data_event[vVantage]
    {
      string:
      {
        if (find_string(data.text,'KEYPADSYSTEMBUTTONSTATUS-',1))
    	{
    	  trash = remove_string(data.text,'KEYPADSYSTEMBUTTONSTATUS-',1)//IN THE EXAMPLE I MENTION IN THE ORIGINAL POST, I SHOULD ONLY HAVE 233,ON NOW
    	  VKeypad = (data.text)
    	}
    	[dvVantage,101] = VKeypad[233,ON]
    	[dvVantage,102] = VKeypad[234,ON]
    	[dvVantage,103] = VKeypad[235,ON]
    	[dvVantage,104] = VKeypad[236,ON]
    	[dvVantage,105] = VKeypad[237,ON]
    	[dvVantage,106] = VKeypad[238,ON]
    	[dvVantage,107] = VKeypad[239,ON]
    	[dvVantage,108] = VKeypad[240,ON]
      }           
    }
    

    If so, when the button is pushed off and the code comes through as saying 233,OFF, will it automatically change the sate of the button, or do I need to do If statements setting the channel on if I get an on response and off if I get an off response? This is ultimately the step I would like to condense in code instead of having two if commands for every button.
    integer VKeypad[500]
    
    data_event[vVantage]
    {
      string:
      {
        if (find_string(data.text,'KEYPADSYSTEMBUTTONSTATUS-',1))
    	{
    	  trash = remove_string(data.text,'KEYPADSYSTEMBUTTONSTATUS-',1)//IN THE EXAMPLE I MENTION IN THE ORIGINAL POST, I SHOULD ONLY HAVE 233,ON NOW
    	  VKeypad[atoi(data.text)] = find_string(data.text,'ON',1)
    	}
    	[dvVantage,101] = VKeypad[233]
    	[dvVantage,102] = VKeypad[234]
    	[dvVantage,103] = VKeypad[235]
    	[dvVantage,104] = VKeypad[236]
    	[dvVantage,105] = VKeypad[237]
    	[dvVantage,106] = VKeypad[238]
    	[dvVantage,107] = VKeypad[239]
    	[dvVantage,108] = VKeypad[240]
      }           
    }
    

    This might work better...
  • Options
    kbeattyAMXkbeattyAMX Posts: 358
    Keep in mind that ATOI works on the first set of ASCII numbers and find_string results in 0 if the string is not found or a positive integer indicating the position of the first instance of the string.
  • Options
    alexsquaredalexsquared Posts: 166
    kbeattyAMX wrote: »
    integer VKeypad[500]
    
    data_event[vVantage]
    {
      string:
      {
        if (find_string(data.text,'KEYPADSYSTEMBUTTONSTATUS-',1))
    	{
    	  trash = remove_string(data.text,'KEYPADSYSTEMBUTTONSTATUS-',1)//IN THE EXAMPLE I MENTION IN THE ORIGINAL POST, I SHOULD ONLY HAVE 233,ON NOW
    	  VKeypad[atoi(data.text)] = find_string(data.text,'ON',1)
    	}
    	[dvVantage,101] = VKeypad[233]
    	[dvVantage,102] = VKeypad[234]
    	[dvVantage,103] = VKeypad[235]
    	[dvVantage,104] = VKeypad[236]
    	[dvVantage,105] = VKeypad[237]
    	[dvVantage,106] = VKeypad[238]
    	[dvVantage,107] = VKeypad[239]
    	[dvVantage,108] = VKeypad[240]
      }           
    }
    

    This might work better...

    Dumb question, but will this place the ON, prior to the 233? If so, will that cause any problems?
    Thanks.
  • Options
    kbeattyAMXkbeattyAMX Posts: 358
    It doesn't matter the position of the string ''ON'. ATOI will process the string without destroying it and FIND_STRING will look for the occurrence of a string without destroying the original string. So whether''ON,233' or '233,ON' The code will function fine. Keep in mind that 'ON' is not ON[dvVantage,233]. 'ON' is just a string of 2 HEX numbers. It's not a command or keyword in this example. When you use ON[device,channel] you are just changing the channel to 1 and OFF[device,channel] you are just changing the channel to 0. Assigning a value to a channel will do the same thing. [device,channel] = 1 will turn on the channel. So assigning the outcome of a boolean operation will do the same. [device,channel] = (variable = 1). So if the variable equals 1 the [device,channel] goes to 1. Now it's ON. You can do this with FIND_STRING because of outcome of FIND_STRING is 0 if it does not find the string and a positive integer if it does find the string.
  • Options
    alexsquaredalexsquared Posts: 166
    kbeattyAMX wrote: »
    You can do this with FIND_STRING because of outcome of FIND_STRING is 0 if it does not find the string and a positive integer if it does find the string.

    This was tremendously helpful. Thank you!
  • Options
    kbeattyAMXkbeattyAMX Posts: 358
    So the array Vkeypad will have an array of numbers with the value of 0 to the possible length of the string in the FIND_STRING function. If VKeypad[233] (pointer to the 233rd position of the array is a value greater than 0 [dvVantage,101] will be 1. If Vkeypad[233] is 0 then [dvVantage,101] will be 0.
  • Options
    alexsquaredalexsquared Posts: 166
    Understood. Thank you again. I look forward to giving this a go.
  • Options
    viningvining Posts: 4,368
    I have no idea how Vantage actually communicates or works but based on the strings in the original post I would handle it something like the code posted below. I would only update a single channel at a time based on what was received but I would store my values in structure so I could update all buttons when a new TP came "on page".

    I think I got carried away with the example it probably wouldn't work with obvious modifcation for real vantage strings but it show another way to skin the can.
    PROGRAM_NAME='TEST'
    
    DEFINE_DEVICE
    
    dvVantage	= 0:5:0 ;
    dvTP1_Vantage	= 10001:1:0 ;
    
    DEFINE_CONSTANT
    
    NUM_PROCESSORS		= 1 ;
    NUM_LINKS_PER_PROC	= 2 ;
    NUM_KEYPADS_PER_LINK	= 32
    NUM_BTNS_PER_KEYPAD	= 8 ;
    LEN_BTNS_NAMES		= 22 ;
    LEN_BUFFER		= 2048 ; //size as needed
    NUM_PARAMS		= 5 ;
    LEN_PARAMS		= 4 ;
    STR_LF			= $0A ;
    
    DEFINE_CONSTANT //LINK 1 KEYPAD BUTTON NAME
    
    VOLATILE CHAR LINK_1_BTN_NAMES[NUM_KEYPADS_PER_LINK][NUM_BTNS_PER_KEYPAD][LEN_BTNS_NAMES] =
    
         {
    	  {//keypad 1             
    	  (*1 *)'KP Btn1',          
    	  (*2 *)'KP Btn2',         
    	  (*3 *)'KP Btn3',          
    	  (*4 *)'KP Btn4',        
    	  (*5 *)'KP Btn5',       	
    	  (*6 *)'KP Btn6',       
    	  (*7 *)'KP Btn7',    
    	  (*8 *)'KP Btn8'
    	  } ,          
    	  
    	  {//keypad 2
    	  (*1 *)'KP Btn1',          
    	  (*2 *)'KP Btn2',         
    	  (*3 *)'KP Btn3',          
    	  (*4 *)'KP Btn4',        
    	  (*5 *)'KP Btn5',       	
    	  (*6 *)'KP Btn6',       
    	  (*7 *)'KP Btn7',    
    	  (*8 *)'KP Btn8'
    	  } ,          
    	  
    	  {//keypad 3
    	  (*1 *)'KP Btn1',          
    	  (*2 *)'KP Btn2',         
    	  (*3 *)'KP Btn3',          
    	  (*4 *)'KP Btn4',        
    	  (*5 *)'KP Btn5',       	
    	  (*6 *)'KP Btn6',       
    	  (*7 *)'KP Btn7',    
    	  (*8 *)'KP Btn8'
    	  } ,      
    	  
    	  {//keypad 4
    	  (*1 *)'KP Btn1',          
    	  (*2 *)'KP Btn2',         
    	  (*3 *)'KP Btn3',          
    	  (*4 *)'KP Btn4',        
    	  (*5 *)'KP Btn5',       	
    	  (*6 *)'KP Btn6',       
    	  (*7 *)'KP Btn7',    
    	  (*8 *)'KP Btn8'
    	  } ,    
    	  
    	  {//keypad 5
    	  (*1 *)'KP Btn1',          
    	  (*2 *)'KP Btn2',         
    	  (*3 *)'KP Btn3',          
    	  (*4 *)'KP Btn4',        
    	  (*5 *)'KP Btn5',       	
    	  (*6 *)'KP Btn6',       
    	  (*7 *)'KP Btn7',    
    	  (*8 *)'KP Btn8'
    	  } ,    
    	  
    	  {//keypad 3
    	  (*1 *)'KP6 Btn1',          
    	  (*2 *)'KP6 Btn2',         
    	  (*3 *)'KP6 Btn3',          
    	  (*4 *)'KP6 Btn4',        
    	  (*5 *)'KP6 Btn5',       	
    	  (*6 *)'KP6 Btn6',       
    	  (*7 *)'KP6 Btn7',    
    	  (*8 *)'KP6 Btn8'
    	  } ,    
    	  
    	  {//keypad 7
    	  (*1 *)'KP Btn1',          
    	  (*2 *)'KP Btn2',         
    	  (*3 *)'KP Btn3',          
    	  (*4 *)'KP Btn4',        
    	  (*5 *)'KP Btn5',       	
    	  (*6 *)'KP Btn6',       
    	  (*7 *)'KP Btn7',    
    	  (*8 *)'KP Btn8'
    	  } ,  
    	       
    	  {//keypad 8
    	  (*1 *)'KP Btn1',          
    	  (*2 *)'KP Btn2',         
    	  (*3 *)'KP Btn3',          
    	  (*4 *)'KP Btn4',        
    	  (*5 *)'KP Btn5',       	
    	  (*6 *)'KP Btn6',       
    	  (*7 *)'KP Btn7',    
    	  (*8 *)'KP Btn8'
    	  } ,   
    	  
    	  {//keypad 9
    	  (*1 *)'KP Btn1',          
    	  (*2 *)'KP Btn2',         
    	  (*3 *)'KP Btn3',          
    	  (*4 *)'KP Btn4',        
    	  (*5 *)'KP Btn5',       	
    	  (*6 *)'KP Btn6',       
    	  (*7 *)'KP Btn7',    
    	  (*8 *)'KP Btn8'
    	  } , 
    
    	  {//keypad 10
    	  (*1 *)'KP Btn1',          
    	  (*2 *)'KP Btn2',         
    	  (*3 *)'KP Btn3',          
    	  (*4 *)'KP Btn4',        
    	  (*5 *)'KP Btn5',       	
    	  (*6 *)'KP Btn6',       
    	  (*7 *)'KP Btn7',    
    	  (*8 *)'KP Btn8'
    	  } 
    	  
    	  //continue
         }
         
    DEFINE_CONSTANT //LINK 1 KEYPAD KP BTNS TO TP BTN/CHNLS
         
    VOLATILE INTEGER LINK_1_TP_CHNLS[NUM_KEYPADS_PER_LINK][NUM_BTNS_PER_KEYPAD] =
    
         {//these are the TP button assigned for feedback of the Vantage KP buttons
    	  {//keypad 1             
    	  (*1 *) 16,          
    	  (*2 *) 4,         
    	  (*3 *) 66,          
    	  (*4 *) 21,        
    	  (*5 *) 75,       	
    	  (*6 *) 9,       
    	  (*7 *) 45,    
    	  (*8 *) 16
    	  } ,          
    	  
    	  {//keypad 2
    	  (*1 *) 11,          
    	  (*2 *) 22,         
    	  (*3 *) 34,          
    	  (*4 *) 24,        
    	  (*5 *) 58,       	
    	  (*6 *) 36,       
    	  (*7 *) 71,    
    	  (*8 *) 18
    	  } ,          
    	  
    	  {//keypad 3
    	  (*1 *) 10,          
    	  (*2 *) 22,         
    	  (*3 *) 30,          
    	  (*4 *) 40,        
    	  (*5 *) 50,       	
    	  (*6 *) 60,       
    	  (*7 *) 70,    
    	  (*8 *) 80
    	  } ,      
    	  
    	  {//keypad 4
    	  (*1 *) 11,          
    	  (*2 *) 12,         
    	  (*3 *) 13,          
    	  (*4 *) 14,        
    	  (*5 *) 15,       	
    	  (*6 *) 16,       
    	  (*7 *) 17,    
    	  (*8 *) 18
    	  } ,    
    	  
    	  {//keypad 5
    	  (*1 *) 21,          
    	  (*2 *) 22,         
    	  (*3 *) 23,          
    	  (*4 *) 24,        
    	  (*5 *) 25,       	
    	  (*6 *) 26,       
    	  (*7 *) 27,    
    	  (*8 *) 28
    	  } ,    
    	  
    	  {//keypad 3
    	  (*1 *) 1,          
    	  (*2 *) 2,         
    	  (*3 *) 3,          
    	  (*4 *) 4,        
    	  (*5 *) 5,       	
    	  (*6 *) 6,       
    	  (*7 *) 7,    
    	  (*8 *) 8
    	  } ,    
    	  
    	  {//keypad 7
    	  (*1 *) 1,          
    	  (*2 *) 2,         
    	  (*3 *) 3,          
    	  (*4 *) 4,        
    	  (*5 *) 5,       	
    	  (*6 *) 6,       
    	  (*7 *) 7,    
    	  (*8 *) 8
    	  } ,  
    	       
    	  {//keypad 8
    	  (*1 *) 1,          
    	  (*2 *) 2,         
    	  (*3 *) 3,          
    	  (*4 *) 4,        
    	  (*5 *) 5,       	
    	  (*6 *) 6,       
    	  (*7 *) 7,    
    	  (*8 *) 8
    	  } ,   
    	  
    	  {//keypad 9
    	  (*1 *) 1,          
    	  (*2 *) 2,         
    	  (*3 *) 3,          
    	  (*4 *) 4,        
    	  (*5 *) 5,       	
    	  (*6 *) 6,       
    	  (*7 *) 7,    
    	  (*8 *) 8
    	  } , 
    
    	  {//keypad 10
    	  (*1 *) 1,          
    	  (*2 *) 2,         
    	  (*3 *) 3,          
    	  (*4 *) 4,        
    	  (*5 *) 5,       	
    	  (*6 *) 6,       
    	  (*7 *) 7,    
    	  (*8 *) 8
    	  } 
    	  
    	  //continue
         }
    
    DEFINE_TYPE //_Keypads
    
    STRUCTURE _Keypads
         
         {
         INTEGER nTP_Btn[NUM_BTNS_PER_KEYPAD] ;
         INTEGER nBtn_State[NUM_BTNS_PER_KEYPAD] ;
         CHAR    cBtn_Name[NUM_BTNS_PER_KEYPAD][LEN_BTNS_NAMES] ;
         }
         
     DEFINE_TYPE //_Links
    
    STRUCTURE _Links
         
         {
         _Keypads sKP[NUM_KEYPADS_PER_LINK]
         }
         
    DEFINE_TYPE //_Porcessors
    
    STRUCTURE _Porcessors
         
         {
         _Links sLink[NUM_LINKS_PER_PROC]
         }
         
    DEFINE_TYPE //_Params
    
    STRUCTURE _Params
         
         {
         CHAR cParam[NUM_PARAMS][LEN_PARAMS] ;
         }
         
    DEFINE_VARIABLE //STRUCTURE
    
    VOLATILE _Porcessors sVantage[NUM_PROCESSORS] ;
    VOLATILE INTEGER nVantage_DeBug = 1 ;
    
    #WARN 'VANTAGE DEBUG ON' 
    
    VOLATILE INTEGER nUpDateAll_Test = 0 ;
    VOLATILE INTEGER nInit_Structure_Test = 0 ;
    VOLATILE INTEGER nLoad_Names_Chnls_Test = 0 ;
    
    DEFINE_FUNCTION fnDevMod_DeBug(CHAR iStr[])
    
         {
         if(nVantage_DeBug)
    	  {
    	  STACK_VAR CHAR cCopyStr[1024] ;
    	  STACK_VAR INTEGER nLineCount ;
    	  
    	  cCopyStr = iStr ;
    	  
    	  nLineCount ++ ;
    	  WHILE(length_string(cCopyStr) > 100)
    	       {
    	       SEND_STRING 0,"'VANTAGE MOD- DEBUG (',itoa(nLineCount),'): ',get_buffer_string(cCopyStr,80)" ;
    	       nLineCount ++
    	       }
    	  if(length_string(cCopyStr))
    	       {
    	       SEND_STRING 0,"'VANTAGE MOD- DEBUG (',itoa(nLineCount),'): ',cCopyStr" ;
    	       }
    	  }
         
         RETURN ;
         } 
    
    DEFINE_FUNCTION fnParse_RXBuffer(CHAR iStr[])
    
         {
         STACK_VAR _Params nData ;
         STACK_VAR INTEGER nFBS ;
         STACK_VAR INTEGER nErr ;
         
         nFBS = find_string(iStr,"'['",1) ;
         if(nFBS)
    	  {
    	  nData.cParam[1] = GET_BUFFER_STRING(iStr,nFBS-1) ;
    	  GET_BUFFER_CHAR(iStr) ;
    	  nFBS = find_string(iStr,"':'",1) ;
    	  if(nFBS)
    	       {
    	       nData.cParam[2] = GET_BUFFER_STRING(iStr,nFBS-1) ;
    	       GET_BUFFER_CHAR(iStr) ;
    	       nFBS = find_string(iStr,"']'",1) ;
    	       if(nFBS)
    		    {
    		    nData.cParam[3] = GET_BUFFER_STRING(iStr,nFBS-1) ;
    		    GET_BUFFER_CHAR(iStr) ;
    		    nFBS = find_string(iStr,"':'",1) ;
    		    if(nFBS)
    			 {
    			 nData.cParam[4] = GET_BUFFER_STRING(iStr,nFBS-1) ;
    			 GET_BUFFER_CHAR(iStr) ;
    			 nFBS = find_string(iStr,"STR_LF",1) ;
    			 if(nFBS)
    			      {
    			      nData.cParam[5] = GET_BUFFER_STRING(iStr,nFBS-1) ;
    			      GET_BUFFER_CHAR(iStr) ;
    			      }
    			 else
    			      {
    			      nErr = 1 ;
    			      }
    			 }
    		    else
    			 {
    			 nErr = 1 ;
    			 }
    		    }
    	       else
    		    {
    		    nErr = 1 ;
    		    }
    	       }
    	  else
    	       {
    	       nErr = 1 ;
    	       }
    	  }
         else
    	  {
    	  nErr = 1 ;
    	  }
    	  
         if(nErr)
    	  {
    	  fnDevMod_DeBug("'fnParse_RXBuffer: Error proccessing return, dumping contents :DEBUG <',ITOA(__LINE__),'>'") ;
    	  
    	  RETURN ;
    	  }
    	  
         fnFB_ProcessData(nData) ;     
         }
         
    DEFINE_FUNCTION fnFB_ProcessData(_Params iData) //load structure and handle feedback
      
         {
         SELECT
    	  {
    	  ACTIVE(iData.cParam[1] == 'K:L:'):
    	       {
    	       STACK_VAR INTEGER nTP_Btn ;
    	              
    	       sVantage[1].sLink[atoi(iData.cParam[2])].sKP[atoi(iData.cParam[3])].nBtn_State[atoi(iData.cParam[4])] = atoi(iData.cParam[5])
    	       
    	       nTP_Btn = sVantage[1].sLink[atoi(iData.cParam[2])].sKP[atoi(iData.cParam[3])].nTP_Btn[atoi(iData.cParam[4])] ;
    	       
    	       fnFB_Update_OneBtn(nTP_Btn,atoi(iData.cParam[5])) ;
    	       }
    	  ACTIVE(iData.cParam[1] == 'Something Else'):
    	       {
    	       //add as needed for dimmer levels etc.
    	       }
    	  ACTIVE(TRUE):
    	       {
    	       fnDevMod_DeBug("'fnFB_UI_Update: Unknown response, p1=',iData.cParam[1],', p2=',iData.cParam[2],
    			      ', p3=',iData.cParam[3],', p4=',iData.cParam[4],' p5=',iData.cParam[5],' :DEBUG <',ITOA(__LINE__),'>'") ;
    	       }
    	  }
         }
    
    DEFINE_FUNCTION fnFB_Update_OneBtn(INTEGER iTP_Btn, INTEGER iState) 
      
         {
         [dvTP1_Vantage,iTP_Btn] = iState ;
         }
    
    DEFINE_FUNCTION fnFB_Update_AllBtns() 
      
         {
         STACK_VAR INTEGER p ;
         STACK_VAR INTEGER l ;
         STACK_VAR INTEGER k ;
         STACK_VAR INTEGER b ;
             
         for(p = 1 ; p <= NUM_PROCESSORS ; p++)
    	  {
    	  for(l = 1 ; l <= NUM_LINKS_PER_PROC ; l++)
    	       {
    	       for(k = 1 ; k <= NUM_KEYPADS_PER_LINK ; k++)
    		    {
    		    for(b = 1 ; b <= NUM_BTNS_PER_KEYPAD ; b++)
    			 {
    			 [dvTP1_Vantage,sVantage[p].sLink[l].sKP[k].nTP_Btn[b]] = sVantage[p].sLink[l].sKP[k].nBtn_State[b] ;
    			 }
    		    }
    	       }
    	  }
         }
         
    DEFINE_FUNCTION fnInit_Structure() 
    
         {
         STACK_VAR INTEGER p ;
         STACK_VAR INTEGER l ;
         STACK_VAR INTEGER k ;
         STACK_VAR INTEGER b ;
            
         for(p = 1 ; p <= NUM_PROCESSORS ; p++)
    	  {
    	  for(l = 1 ; l <= NUM_LINKS_PER_PROC ; l++)
    	       {
    	       for(k = 1 ; k <= NUM_KEYPADS_PER_LINK ; k++)
    		    {
    		    for(b = 1 ; b <= NUM_BTNS_PER_KEYPAD ; b++)
    			 {
    			 sVantage[p].sLink[l].sKP[k].cBtn_Name[b] = "'P-',itoa(p),', L-',itoa(l),', K-',itoa(k),', B-',itoa(b)" ;
    			 sVantage[p].sLink[l].sKP[k].nTP_Btn[b] = b ;
    			 sVantage[p].sLink[l].sKP[k].nBtn_State[b] = b + 10 ;
    			 }
    		    }
    	       }
    	  }
         }
         
    DEFINE_FUNCTION fnLoad_Names_Chnls()//modified for testing 
    
         {
         STACK_VAR INTEGER p ;
         STACK_VAR INTEGER l ;
         STACK_VAR INTEGER k ;
         STACK_VAR INTEGER b ;
         STACK_VAR INTEGER nLengthArry ; //since I didn't create the entire array  of constant values for name
         
         nLengthArry = length_array(LINK_1_TP_CHNLS) ;
         fnDevMod_DeBug("'DEFINE_START: Lenght Array LLINK_1_TP_CHNLS =',itoa(nLengthArry),' :DEBUG <',ITOA(__LINE__),'>'") ;
         
         //for(p = 1 ; p <= NUM_PROCESSORS ; p++)
    	  //{
    	  //for(l = 1 ; l <= NUM_LINKS_PER_PROC ; l++)
    	       //{
    	       for(k = 1 ; k <= nLengthArry ; k++)
    		    {
    		    for(b = 1 ; b <= NUM_BTNS_PER_KEYPAD ; b++)
    			 {
    			 sVantage[1].sLink[1].sKP[k].cBtn_Name[b] = LINK_1_BTN_NAMES[k][b] ;
    			 sVantage[1].sLink[1].sKP[k].nTP_Btn[b] = LINK_1_TP_CHNLS[k][b] ;
    			 }
    		    }
    	      // }
    	 // }
        //}
         
    DEFINE_START
     
    WAIT 300
         {
         fnInit_Structure() ;
         fnLoad_Names_Chnls() ;
         }
     
    DEFINE_EVENT //DATA_EVENT[dvVantage]
    
    DATA_EVENT[dvVantage]
         
         {
         STRING:
    	  {
    	  LOCAL_VAR CHAR cRX_Buffer[LEN_BUFFER] ;
    	  
    	  cRX_Buffer = "cRX_Buffer,DATA.TEXT" ;
    	  
    	  WHILE(find_string(cRX_Buffer,"STR_LF",1))//this assume the device send one response at a time and each response terminates w/ $0A (LF)
    	       {
    	       fnParse_RXBuffer(REMOVE_STRING(cRX_Buffer,"STR_LF",1)) ;
    	       }
    	  }
         }
    
    DEFINE_PROGRAM
    
    if(nUpDateAll_Test)
         {
         fnFB_Update_AllBtns() ;
         nUpDateAll_Test = 0 ;
         }
         
    if(nInit_Structure_Test)
         {
         fnInit_Structure()  ;
         nInit_Structure_Test = 0 ;
         }
         
    if(nLoad_Names_Chnls_Test)
         {
         fnLoad_Names_Chnls() ;
         nLoad_Names_Chnls_Test = 0 ;
         }     
         
    

    Like I said I got a little carried away and needed a change from what I was doing. Hope this gives you some ideas!

    PS some of the initalization values assigned were just to see something other than zero. The Init intialization would normally be 0 but I can't see if it works so I fudged it for testing.
  • Options
    a_riot42a_riot42 Posts: 1,624
    I knew that had to be Vinings code. He must get paid by the character :)
    I've never seen a nested for loop 4 levels deep before, except maybe in chess software. Its something to behold.
    Paul
    DEFINE_FUNCTION fnFB_Update_AllBtns() 
    {
       STACK_VAR INTEGER p ;
       STACK_VAR INTEGER l ;
       STACK_VAR INTEGER k ;
       STACK_VAR INTEGER b ;
             
       for(p = 1 ; p <= NUM_PROCESSORS ; p++)
       {
        for(l = 1 ; l <= NUM_LINKS_PER_PROC ; l++)
        {
           for(k = 1 ; k <= NUM_KEYPADS_PER_LINK ; k++)
           {
    	  for(b = 1 ; b <= NUM_BTNS_PER_KEYPAD ; b++)
    	 {
    	     [dvTP1_Vantage,sVantage[p].sLink[l].sKP[k].nTP_Btn[b]] = sVantage[p].sLink[l].sKP[k].nBtn_State[b] ;
    	 }
          }
        }
      }
    }
    
  • Options
    viningvining Posts: 4,368
    a_riot42 wrote: »
    I knew that had to be Vinings code. He must get paid by the character :)
    I've never seen a nested for loop 4 levels deep before, except maybe in chess software. Its something to behold.
    Paul
    DEFINE_FUNCTION fnFB_Update_AllBtns() 
    {
       STACK_VAR INTEGER p ;
       STACK_VAR INTEGER l ;
       STACK_VAR INTEGER k ;
       STACK_VAR INTEGER b ;
             
       for(p = 1 ; p <= NUM_PROCESSORS ; p++)
       {
        for(l = 1 ; l <= NUM_LINKS_PER_PROC ; l++)
        {
           for(k = 1 ; k <= NUM_KEYPADS_PER_LINK ; k++)
           {
    	  for(b = 1 ; b <= NUM_BTNS_PER_KEYPAD ; b++)
    	 {
    	     [dvTP1_Vantage,sVantage[p].sLink[l].sKP[k].nTP_Btn[b]] = sVantage[p].sLink[l].sKP[k].nBtn_State[b] ;
    	 }
          }
        }
      }
    }
    

    I'm open to sugesstions for alternatives. :) Keep in mind this only runs once when a new TP comes "on page" so to me in my simple mind this mehod makes perfect sense. How would you go about writing code for a device that uses this type of addressing scheme.

    BTW, I'm totally in favor of all forum member sharing their code since it can only improve AMX by improving their dealers so let us see how in your mind it should be done. Then maybe someone else will post a different idea and we'll all benefit.

    FYI, it's my company so my time is "my time" and I don't pay myself for writing code. I only get paid when there's a profit after the job is complete.
  • Options
    a_riot42a_riot42 Posts: 1,624
    With four for loops, if you have 10 elements in each array your loop runs 10^4 = 10,000 times, probably not too hard on the processor. But if the values were a bit bigger,

    NUM_PROCESSORS = 5
    NUM_LINKS_PER_PROC = 20
    NUM_KEYPADS_PER_LINK = 256
    NUM_BTNS_PER_KEYPAD = 16

    then it runs 409,600 times. It'll get slow fast. I generally do lazy panel updating, meaning I never update the panel unless I absolutely have to, ie: feedback has changed, and the user is looking at it right now. In the case of a panel coming online, I'll only update whatever's on the page they will see once online. One of the rare occasions when my natural laziness has side benefits.
    Paul
  • Options
    Update...still needing help

    Ok, so I've been working with AMX directly on this, and one of the tech guys was kind enough to send me an AXS file to do what I'm wanting to do. The only caveat is that you set it up so that the button #'s on the TP, match your VID (Button address) on vantage. The control of the vantage system is working just fine. The feedback, however, is not. I verified with my guy that it needs to match the channel code of the button. Any thoughts, looking into this code, as to what may be causing that?
Sign In or Register to comment.