Home AMX User Forum NetLinx Studio

Multi-D Arrays Question

I am trying to shorten the code I wrote for a 232-controlled relay unit. I don't know what type of variable, constant, array, etc. to use for this. Here is what I have:
BUTTON_EVENT[dvCV7Tp,40]  //Relay8Net Zone 1 (open)
{
	PUSH:
	{
		If (nRelay2Status = 1)
		{
			CANCEL_WAIT 'relay 2 on'
			SEND_STRING dvRelay, "$40,$01,$42"  //releases relay 2
			
			
		}
		If (nRelay3Status = 1)
		{
			CANCEL_WAIT 'relay 3 on'
			SEND_STRING dvRelay, "$40,$01,$43"  //releases relay 3
		}
		Wait 2  //delay needed to give relay unit time to recover after above command	
		SEND_STRING dvRelay, "$40,$01,$31"
		Wait 50 'relay 1 on'
		SEND_STRING dvRelay, "$40,$01,$41"
		
	}
}
BUTTON_EVENT[dvCV7Tp,41]  //Relay8Net Zone 2 (close)
{
	PUSH:
	{
		If (nRelay1Status = 1)
			{
				CANCEL_WAIT 'relay 1 on'
				SEND_STRING dvRelay, "$40,$01,$41"
				
			}
		IF (nRelay3Status = 1)
			{
				CANCEL_WAIT 'relay 3 on'
				SEND_STRING dvRelay, "$40,$01,$43"
			}
		Wait 2  //delay needed to give relay unit time to recover after above command
		SEND_STRING dvRelay, "$40,$01,$32"
		Wait 50 'relay 2 on'
		SEND_STRING dvRelay, "$40,$01,$42"
		
	}
}
BUTTON_EVENT[dvCV7Tp,42]  //Relay8Net Zone 3(STOP)
{
	PUSH:
	{
			If (nRelay1Status=1)
				{
				CANCEL_WAIT 'relay 1 on'
				SEND_STRING dvRelay, "$40,$01,$41"
				}
			If (nRelay2Status=1)
				{
				CANCEL_WAIT 'relay 2 on'
				SEND_STRING dvRelay, "$40,$01,$42"
				}
			Wait 2  //delay needed to give relay unit time to recover after above command
			SEND_STRING dvRelay, "$40,$01,$33"
			Wait 50 'relay 3 on'
			SEND_STRING dvRelay, "$40,$01,$43"
		
	}
}
Basically, I have the relays programmed so that when one relay is triggered, the other two open. (Its for shades UP, DOWN, and STOP). As you can see, I am accomplishing this with the use of a variable for each relay. I would like to stack the button events, but I think I need a multi-dimensional array and get_lasts to make this happen. Something like:
VOLATILE INTEGER nTotal_Relays[] = {43,44,45}
VOLATILE INTEGER Curr_Relay
BUTTON_EVENT[dvCV7Tp,nTotal_Relays]  //relay control, buttons 43,44,45
{
	PUSH:
	{
		
		Curr_Relay = get_last(nTotal_Relays)  //chooses relay1,2or3
		Switch (Curr_Relay)
		{
			Case 43:
			{}
			Case 44:
			{}
			Case 45:
			{}
		}
		
	} 
} 
Where I get stuck is trying to determine the state of my other variables, one for each relay. I was thinking of a multi-dimensional array for those as well, so that I could store the 1 and 0 values for each, and then simply reference the array, but what would I do if i want it to cross-check multiple items to then send the appropriate string, as I did the long way, up above? I don't think I have a grasp on the Multi's yet.

Comments

  • ericmedleyericmedley Posts: 4,177
    Well, firstly there a much much simpler way to accomplish this: define_mutually_exclusive.

    DEFINE_MUTUALLY_EXCLUSIVE

    ( [dv_Relay,1] , [dv_relay,2], [dv_relay,3] , etc... )

    or if your channels are consecutive

    ( [dv_realy,1] .. [dv_realy,5] )

    this will kill any on relays when you turn on some other relay in the bunch automatically.

    now for the array question.

    I would probably run the array through a for loop, check for new on state and kill all, then tun on new relay.

    Hope that helps
    e
  • jjamesjjames Posts: 2,908
    Well, I'd use arrays of course and you're on the right track. Instead of having the 3 variable names, I'd have an integer array with a length of three (VOLATILE INTEGER relays[3]).

    The nice thing about arrays is you can loop them. The problem with your code is that you're using named waits, which you wouldn't be able to avoid a switch/case. What you could use instead of named waits would be timelines. This way, in the start of your button event you can run a quick for-loop to check if the relay was on or off. Sort of something like this:
    FOR(i=1;i<=3;i++)
    {
    	IF(relays[i] && i != currRelay)
    	{
    		// Equal to canceling a named wait
    		IF(TIMELINE_ACTIVE(RELAY_TL[i]))
    			TIMELINE_KILL(RELAY_TL[i]);
    		
    		// Send the string to the specific relay
    		SEND_STRING dvRelay, "$40,$01,$40 + i"
    	}
    }
    
    

    This would check only the relays, if the timeline is active, kill it (essentially destroying a named wait), and the string is modified by which relay we're checking. Storing things in variables can be rather powerful and used to shorten a lot of code.

    The later in the button event, you'd go on to recreate any timelines, again modifying the strings based on which relay we're controlling. (I.e. "$40,$01,$40 + CurRelay" or "$40,$01,$30 + CurRelay")

    One thing on the GET_LAST, I'd store that value in a STACK_VAR rather than a global variable. This way it's destroyed when the code is finished. No need to keep the value after the button event is finished.

    Just my 2 cents.
  • Spire_JeffSpire_Jeff Posts: 1,917
    ericmedley wrote: »
    Well, firstly there a much much simpler way to accomplish this: define_mutually_exclusive.

    DEFINE_MUTUALLY_EXCLUSIVE

    ( [dv_Relay,1] , [dv_relay,2], [dv_relay,3] , etc... )

    or if your channels are consecutive

    ( [dv_realy,1] .. [dv_realy,5] )

    this will kill any on relays when you turn on some other relay in the bunch automatically.

    I don't think this will work as it appears the relays reside on a third-party controller.

    As to the code question, I would probably create a functions for sending the commands like so:
    define_constant 
    integer RelayOn = 1;
    integer RelayOff = 0;
    integer nRelayBtns[] = {40,41,42};
    
    define_variable
    integer nActiveRelay;
    
    define_function fnSendRelayCmd(integer nRelay, integer nState){
      stack_var char cmd;
      cmd = $30 + ((!nState) << 4) + nRelay;
      send_string dvRelay,"$40,$01,cmd";
      if(nState){
        nActiveRelay = nRelay;
        cancel_wait 'PulseTime';//Reset off delay.
        wait 50 'PulseTime' fnSendRelayCmd(nActiveRelay, RelayOff); // Turn off relay after 5 seconds.
      }
      else if(nRelay == nActiveRelay)
         nActiveRelay = 0;
    }
    
    define_function fnDoExclusiveRelayOn(integer nRelay){
    	if(nActiveRelay){
    		if(nRelay <> nActiveRelay){
    			fnSendRelayCmd(nActiveRelay,RelayOff);
    			wait 2 fnSendRelayCmd(nRelay,RelayOn);
    		}
    	}else{
    		fnSendRelayCmd(nRelay,RelayOn);
    	}
    }
    define_event
    button_event[dvCv7Tp,nRelayBtns]{
    	push:{
    		fnDoExclusiveRelayOn(get_last(nRelayBtns));
    	}
    }
    

    I think I have the logic correct, but I generally code a 1 in place of a 0 on the first try and have to find it after loading and testing :)

    Jeff
  • vegastechvegastech Posts: 369
    Sometimes I think u guys are trying to make my head explode... :) These responses definitely give me a lot to work on. Thanks! (No, seriously)
Sign In or Register to comment.