Home AMX User Forum NetLinx Modules & Duet Modules

First Module Please Help

I have not yet gone to the training yet and I have some basic programming mainly AutoIt scripts. So I already know I have a system that is coming up that has 10 Leviton ViziaRF switches, this is all they want the system to control, via RS-232. So I am writing a module for this just incase I need it again I can just modify it if I need to go over 10 switches. I will be adding in scenes latter on when I get my hands on the system. So what I did was create 3 arrays for One array is all 10 of the Bright buttons, another for the Dim, and another for an On/Off toggle button. The buttons are numbered xzz, x = function (Bright, Dim, Toggle) zz = zone. Here is where I am at now. I know I probably have the Define Device of the RS-232 module set wrong. Any insight would be great.

Source
PROGRAM_NAME='Vizia Test'
(***********************************************************)

DEFINE_DEVICE

dvTP = 128:1:0


DEFINE_VARIABLE

//Format is 1 = Bright and then the zone (switch) number upto 11
DEVCHAN dcViziaBright[] = 
{
    {dvTP, 12},	
    {dvTP, 13},	
    {dvTP, 14},	
    {dvTP, 15},	
    {dvTP, 16},	
    {dvTP, 17},	
    {dvTP, 18},	
    {dvTP, 19},	
    {dvTP, 110},
    {dvTP, 111}
}

//Format is 2 = Dim and then the zone (switch) number upto 11
DEVCHAN dcViziaDim[] = 
{
    {dvTP, 22},
    {dvTP, 23},
    {dvTP, 24},
    {dvTP, 25},
    {dvTP, 26},
    {dvTP, 27},
    {dvTP, 28},
    {dvTP, 29},
    {dvTP, 210},
    {dvTP, 211}
}

//Format is 3 = Toggle On/Off and then the zone (switch) number upto 11
DEVCHAN dcViziaToggle[] =
{
    {dvTP, 32},
    {dvTP, 33},
    {dvTP, 34},
    {dvTP, 35},
    {dvTP, 36},
    {dvTP, 37},
    {dvTP, 38},
    {dvTP, 39},
    {dvTP, 310},
    {dvTP, 311}
}

DEFINE_START



DEFINE_MODULE 'ViziaRF' md1ViziaModule(dcViziaBright, dcViziaDim, dcViziaToggle)

Module
MODULE_NAME='ViziaRF'	(DEVCHAN dcViziaBright[],
			 DEVCHAN dcViziaDim[],
			 DEVCHAN dcViziaToggle[])


DEFINE_DEVICE

dvViziaRF = 1:7:0



DEFINE_VARIABLE
INTEGER nSwitch
INTEGER nFunc
INTEGER nStatus


DEFINE_EVENT

BUTTON_EVENT[dcViziaBright]
{
    
    PUSH:
	IF (BUTTON.INPUT.CHANNEL < 100){ SEND_COMMAND dvViziaRF, "'>N',ITOA(BUTTON.INPUT.CHANNEL-10),'BI'" }
	ELSE { SEND_COMMAND dvViziaRF, "'>N',ITOA(BUTTON.INPUT.CHANNEL-100),'BI'" }
}

BUTTON_EVENT[dcViziaDim]
{
    
    PUSH:
	IF (BUTTON.INPUT.CHANNEL < 200){ SEND_COMMAND dvViziaRF, "'>N',ITOA(BUTTON.INPUT.CHANNEL-20),'DI'" }
	ELSE { SEND_COMMAND dvViziaRF, "'>N',ITOA(BUTTON.INPUT.CHANNEL-200),'DI'" }
}

BUTTON_EVENT[dcViziaToggle]
{
    
    PUSH:
	IF (BUTTON.INPUT.CHANNEL < 300)
	    { SEND_COMMAND dvViziaRF, "'>?N',ITOA(BUTTON.INPUT.CHANNEL-30)} = nStatus
		IF (nStatus <> 0) {SEND_COMMAND dvViziaRF, "'>N',ITOA(BUTTON.INPUT.CHANNEL-30), 'OF'"}
		ELSE {SEND_COMMAND dvViziaRF, "'>N',ITOA(BUTTON.INPUT.CHANNEL-30), 'ON'"}
	ELSE 
	    { SEND_COMMAND dvViziaRF, "'>N',ITOA(BUTTON.INPUT.CHANNEL-300)} = nStatus
		IF (nStatus <> 0) {SEND_COMMAND dvViziaRF, "'>N',ITOA(BUTTON.INPUT.CHANNEL-300), 'OF'"}
		ELSE {SEND_COMMAND dvViziaRF, "'>N',ITOA(BUTTON.INPUT.CHANNEL-300), 'ON'"}
}

I just notice that I get a syntax error when compiling the module, at the Toggle button, so I am looking at that right now
«13

Comments

  • jjamesjjames Posts: 2,908
    May I first say . . . less lines do not make for better code. Don't consolidate so much, break it out, use the brackets, and you'll see your errors MUCH easier. Plus, if you write code like that - very few are going to want to debug it.

    That being said, here's your toggle event all bracketed out . . . you should be able to find the problem MUCH easier.
    BUTTON_EVENT[dcViziaToggle]
    {
        
    	PUSH:
    	{
    		IF (BUTTON.INPUT.CHANNEL < 300)
    		{
    			SEND_COMMAND dvViziaRF, "'>?N',ITOA(BUTTON.INPUT.CHANNEL-30)
    		} = nStatus
    		IF (nStatus <> 0)
    		{
    			SEND_COMMAND dvViziaRF, "'>N',ITOA(BUTTON.INPUT.CHANNEL-30), 'OF'"
    		}
    		ELSE
    		{
    			SEND_COMMAND dvViziaRF, "'>N',ITOA(BUTTON.INPUT.CHANNEL-30), 'ON'"
    		}
    		ELSE 
    		{
    			SEND_COMMAND dvViziaRF, "'>N',ITOA(BUTTON.INPUT.CHANNEL-300)
    		} = nStatus
    		IF (nStatus <> 0)
    		{
    			SEND_COMMAND dvViziaRF, "'>N',ITOA(BUTTON.INPUT.CHANNEL-300), 'OF'"
    		}
    		ELSE
    		{
    			SEND_COMMAND dvViziaRF, "'>N',ITOA(BUTTON.INPUT.CHANNEL-300), 'ON'"
    		}
    	}
    }
    
  • mpullinmpullin Posts: 949
    Agreed
    BUTTON_EVENT[dcViziaToggle]
    {
        
        PUSH:
    	IF (BUTTON.INPUT.CHANNEL < 300)
    	    { SEND_COMMAND dvViziaRF, "'>?N',ITOA(BUTTON.INPUT.CHANNEL-30)} = nStatus
    		IF (nStatus <> 0) {SEND_COMMAND dvViziaRF, "'>N',ITOA(BUTTON.INPUT.CHANNEL-30), 'OF'"}
    		ELSE {SEND_COMMAND dvViziaRF, "'>N',ITOA(BUTTON.INPUT.CHANNEL-30), 'ON'"}
    	ELSE 
    	    { SEND_COMMAND dvViziaRF, "'>N',ITOA(BUTTON.INPUT.CHANNEL-300)} = nStatus
    		IF (nStatus <> 0) {SEND_COMMAND dvViziaRF, "'>N',ITOA(BUTTON.INPUT.CHANNEL-300), 'OF'"}
    		ELSE {SEND_COMMAND dvViziaRF, "'>N',ITOA(BUTTON.INPUT.CHANNEL-300), 'ON'"}
    }
    
    = find the needle
    BUTTON_EVENT[dcViziaToggle]
    {
        
    	PUSH:
    	{
    		IF (BUTTON.INPUT.CHANNEL < 300)
    		{
    			SEND_COMMAND dvViziaRF, "'>?N',ITOA(BUTTON.INPUT.CHANNEL-30)
    		} = nStatus
    		IF (nStatus <> 0)
    		{
    			SEND_COMMAND dvViziaRF, "'>N',ITOA(BUTTON.INPUT.CHANNEL-30), 'OF'"
    		}
    		ELSE
    		{
    			SEND_COMMAND dvViziaRF, "'>N',ITOA(BUTTON.INPUT.CHANNEL-30), 'ON'"
    		}
    		ELSE 
    		{
    			SEND_COMMAND dvViziaRF, "'>N',ITOA(BUTTON.INPUT.CHANNEL-300)
    		} = nStatus
    		IF (nStatus <> 0)
    		{
    			SEND_COMMAND dvViziaRF, "'>N',ITOA(BUTTON.INPUT.CHANNEL-300), 'OF'"
    		}
    		ELSE
    		{
    			SEND_COMMAND dvViziaRF, "'>N',ITOA(BUTTON.INPUT.CHANNEL-300), 'ON'"
    		}
    	}
    }
    
    = find the haystack :)
  • Thanks for the insight on breaking it out. As for the IF statements that both have posted does not do exactly what I need it to do. You are only querying the status ("'>?N") only if the button is less than 300, I also need to do it for the two switches that would be 310 and 311. So this is what I have so far broken out with the brackets. I just may be getting confussed with the way I normally do nested IF statements in other languages, can't wait for the classes
    BUTTON_EVENT[dcViziaToggle]
    {
    
        PUSH:
    	IF (BUTTON.INPUT.CHANNEL < 300) // If switches 2 thru 9
    
    	{    //This is the line I am getting the syntax error on
    
    	    SEND_COMMAND dvViziaRF, "'>?N',ITOA(BUTTON.INPUT.CHANNEL-30")" == nStatus //Check status
    	    IF (nStatus <> 0) // If status is on
    	    {
    		SEND_COMMAND dvViziaRF, "'>N',ITOA(BUTTON.INPUT.CHANNEL-30), 'OF'" //Set switch to Off
    	    }
    	    ELSE // if switch is Off
    	    {
    		SEND_COMMAND dvViziaRF, "'>N',ITOA(BUTTON.INPUT.CHANNEL-30), 'ON'" //Set switch to On
    	    }
    	}
    	ELSE // For switches 10 and 11
    	{
    	    SEND_COMMAND dvViziaRF, "'>N',ITOA(BUTTON.INPUT.CHANNEL-300)" == nStatus //Check status
    	    IF (nStatus <> 0)
    	    {
    		SEND_COMMAND dvViziaRF, "'>N',ITOA(BUTTON.INPUT.CHANNEL-300), 'OF'" //Set switch to Off
    	    }
    	    ELSE
    	    {
    		SEND_COMMAND dvViziaRF, "'>N',ITOA(BUTTON.INPUT.CHANNEL-300), 'ON'" //Set switch to On
    	    }
    	}
    }
    
  • mpullinmpullin Posts: 949
    What's the point of passing all these DEVCHAN arrays into your module if you're just going to use BUTTON.INPUT.CHANNEL? GET_LAST() is your friend.
  • jjamesjjames Posts: 2,908
    SEND_COMMAND dvViziaRF, "'>?N',ITOA(BUTTON.INPUT.CHANNEL-30")" == nStatus

    I'm curious, what are you trying to do here?
  • jjames wrote: »
    SEND_COMMAND dvViziaRF, "'>?N',ITOA(BUTTON.INPUT.CHANNEL-30")" == nStatus

    I'm curious, what are you trying to do here?

    Get the value of the switch gives the dimmer percentage 0 is off and set the variable to this value. the command to do this is >?N1 would do node (switch) 1
  • jjamesjjames Posts: 2,908
    Alright . . . :D

    You're making the same mistakes that I made when I first started programming.

    SEND_COMMANDs are meant for virtual / AMX devices
    SEND_STRINGS are meant for real devices

    So, to send the "command" to the device, you'll need to use SEND_STRING instead of SEND_COMMAND.

    Next, you'll need to parse the received data. So, you're going to need a whole new section: the DATA_EVENT section. You'll assign nStatus there. But since 99.99% of devices can't respond faster than the processor, you're going to need to wait until you get a response back before proceeding with what to do with the answer.
    DATA_EVENT[dvViziaRF]
    {
       STRING: // Is triggered when you get a string back from the device
       {
          // Process the string; you can use DATA.TEXT which is the text that is received in this event
       }
    }
    

    See if that makes sense....
  • Ok.. JJames thanks for your help
    Next, you'll need to parse the received data. So, you're going to need a whole new section: the DATA_EVENT section. You'll assign nStatus there. But since 99.99% of devices can't respond faster than the processor, you're going to need to wait until you get a response back before proceeding with what to do with the answer.

    I understand that now I just looked at some other modules. Now the question that rises up is that I am using the BUTTON.INPUT.CHANNEL to figure out the switch number am I able to set a variable in the BUTTON_EVENT to the zone and pass that to the DATA_EVENT, not sure if I am going about this the right way.
  • I found a post that had the code used in a UI and Comm module which is helping me. I rewrote most of the code again and right now I am working on the DATA_EVENT section and have a question if this is would work. I am receiving "<NxxxLyyy" where xxx is the node number and yyy is the brightness level. I need to strip this into two variables as Nxxx and the other is yyy. The String manipulations are a little different than what I am use to. This is what I am doing, if there is a better way, could some one point me into the right direction, not asking for someone to write it for me just guidance. This is to goggle On/Off the light.
    DATA_EVENT[vdvViziaRF]
    {
        STRING:
        {
    	STACK_VAR char nData
    	STACK_VAR char nStatus
    	STACK_VAR char nNode
    	
    	SEND_STRING 0,"'Rcvd from Comm:',DATA.TEXT"
    
    	// need to verify that 3 digits is received on all messages for xxx and yyy
    
    	nData = ITOA(DATA.TEXT)	                                // DATA Text is <NxxxLyyy x is Node L light level
    	nNode = MID_STRING(nData, 2, 4)                     // returns Nxxx
    	nStatus  = REMOVE_STRING (nData,'L',1)         //  returns yyy from the data
    	If (nStatus <> 000)                                            // if light is not off
    	{
    	    SEND_COMMAND vdvViziaRF, "'>', nNode, 'OF'"      // turn light off
    	}
    	ELSE
    	{
    	    SEND_COMMAND vdvViziaRF, "'>, nNode, 'ON'"     //turn light on
    	}
        }
    }
    
  • jjamesjjames Posts: 2,908
    You're on the right track. You'll get there, trust me. I'll take a stab at "critiquing" the code.
    DATA_EVENT[vdvViziaRF]
    
    It appears you're parsing the virtual device and not the real device. Is the real device dvViziaRF?

    Next.....
    STACK_VAR char nData
    STACK_VAR char nStatus
    STACK_VAR char nNode
    
    Without defining the size of each CHAR variable, they'll only be one character long. Need to do something like this:
    STACK_VAR char cData[20]
    STACK_VAR integer nStatus
    STACK_VAR integer nNode
    
    Not sure how big your variables need to be, so increase or decrease them accordingly. And I would use INTEGERs rather than CHARs for nStatus & nNode. See below.

    Next...
    nData = ITOA(DATA.TEXT)
    
    First, the incoming data is already "ASCII", so there's no need to convert it. ITOA is converting an INTEGER to an ASCII (or CHAR) variable. What you'll probably want to do is capture the entire string and manipulate it from there.

    You could do something for the manipulation like this (and let's assume cData has the data we need to parse):
    // cData = N123L567
    REMOVE_STRING(cData,'N',1); // Remove N - cData now equals 123L567
    nNode = ATOI(REMOVE_STRING(cData,'L',1)); // cData now equals 567
    nStatus = ATOI(cData);
    
    ATOI will convert the numbers in a string up to the first letter into an INTEGER

    Then, make you evaluations
    IF(nStatus > 0) // if it's not off . . .
    {
     // SEND_STRING, device, Turn it off
    }
    ELSE // it is off . . .
    {
      // SEND_STRING, device, Turn it on
    }
    
    Take a look at this tech note, it should help you with parsing incoming data.
    http://amx.com/techsupport/techNote.asp?id=616

    Also, for Hungarian notation, I generally use this set of rules...
    dv - DEVICE, PHYSICAL
    vdv - DEVICE, VIRTUAL
    dc - DEVICE,CHANNEL
    s - CONSTANT LITERAL STRING EXPRESSION
    c - 8 BIT CHARACTER
    n - 16 BIT NUMERIC
    sn - SIGNED 16 BIT NUMERIC

    dv_ - DEVICE ARRAY
    ch_ - CHANNEL ARRAY
    dc_ - DEVICE,CHANNEL ARRAY
    c_ - 8 BIT CHARACTER ARRAY
    n_ - 16 BIT NUMERIC ARRAY
    sn_ - SIGNED 16 BIT NUMERIC ARRAY

    Hope this helps!
  • In creating modules, I would shoot for a COMM module that would use all of the available channels on the Leviton. You could interact with that module with Channels or Send Commands to the Virtual Device. The Comm Module would respond with the current values on levels and channel for the real device.

    After that, create a UI Module that integrates the user interface (ie. Button Channels).

    You could use commands link: TOGGLE-2 or DIM-5 to control the Comm Module. That is if you want to go this far....
  • The code that I posted and JJames modified and made suggests on was for the UI module. This is what I have for the Comm module so far.

    JJames you help is extremely appreciated thank you.
    MODULE_NAME='ViziaRF_Comm' ( DEV vdvDEV, DEV dvDEV )
    (***********************************************************)
    (***********************************************************)
    (*  FILE_LAST_MODIFIED_ON: 04/04/2006  AT: 11:33:16        *)
    (***********************************************************)
    (* System Type : NetLinx                                   *)
    (***********************************************************)
    (* REV HISTORY:                                            *)
    (***********************************************************)
    (*
        $History: $
    *)    
    
    
    DEFINE_DEVICE
    
    
    DEFINE_VARIABLE
    
    VOLATILE CHAR cBUFFER[1000]             // BUFFER FOR PHSICAL DEVICE RESPONSES
    VOLATILE CHAR cCMD_QUEUE[1000]          // STORES STRINGS TO BE SENT TO THE DEVICE
    VOLATILE CHAR cLAST_COMMAND[5]          // HOLDS LAST COMMAND SENT TO DEVICE
    VOLATILE INTEGER nWAITING = 0           // INDICATES IF WE ARE WAITING FOR A RESPONSE OR NOT
    VOLATILE CHAR cCMD[9]                 	// COMMAND FROM UI
    VOLATILE CHAR cSCMD[9]                 	// COMMAND TO ViziaRF
    VOLATILE INTEGER nDEBUG = 0             // TRACKS THE ON/OFF STATE OF THE DEBUG MESSAGES
    
    (***********************************************************)
    (*               LATCHING DEFINITIONS GO BELOW             *)
    (***********************************************************)
    DEFINE_LATCHING
    
    (***********************************************************)
    (*       MUTUALLY EXCLUSIVE DEFINITIONS GO BELOW           *)
    (***********************************************************)
    DEFINE_MUTUALLY_EXCLUSIVE
    
    (***********************************************************)
    (*        SUBROUTINE/FUNCTION DEFINITIONS GO BELOW         *)
    (***********************************************************)
    (**************************************)
    (* NAME: QUE COMMAND                  *)
    (* PURPOSE: ADD A COMMAND TO THE QUE  *)
    (**************************************)
    DEFINE_FUNCTION QUE_CMD (CHAR cCMD[])
    {
        IF ((LENGTH_STRING(cCMD_QUEUE) + LENGTH_STRING(cCMD)) <= MAX_LENGTH_ARRAY(cCMD_QUEUE))
        {
            cCMD_QUEUE = "cCMD_QUEUE,cCMD"
        }
        ELSE IF (nDEBUG) { SEND_STRING 0,"'ERRORM=Queue full - command rejected.'" }(* QUEUE IS FULL *)
        IF (!nWAITING) 
        { 
           SEND_CMD() 
        }
    }
    
    (********************************************************)
    (* SEND A COMMAND TO THE DEVICE AND WAIT FOR A RESPONSE *)
    (********************************************************)
    DEFINE_FUNCTION SEND_CMD()
    {
    
        STACK_VAR INTEGER N
        
        IF (LENGTH_STRING(cCMD_QUEUE) >=5  AND !nWAITING)
        {
            cSCMD = cCMD_QUEUE
            SEND_STRING dvDEV, "cSCMD"
            ON[nWAITING]
            WAIT 20 'WAIT FOR RESPONSE'
            {
                IF (nDEBUG) 
    	    { 
    		SEND_STRING 0, "'NO RESPONSE RECEIVED; SENDING NEXT CMD'" 
    		cSCMD = ""
    		
    	    }
                OFF[nWAITING]
            }
        }
    }
    
    
    (***********************************************************)
    (*                STARTUP CODE GOES BELOW                  *)
    (***********************************************************)
    DEFINE_START
    
    CREATE_BUFFER dvDEV, cBUFFER    // PHYSICAL DEVICE BUFFER
    (***********************************************************)
    (*                THE EVENTS GO BELOW                      *)
    (***********************************************************)
    DEFINE_EVENT
    
    (***********************************************************)
    (*            THE ACTUAL PROGRAM GOES BELOW                *)
    (***********************************************************)
    DEFINE_PROGRAM
    
    SEND_CMD ()
    (***********************************************************)
    (*                     END OF PROGRAM                      *)
    (*        DO NOT PUT ANY CODE BELOW THIS COMMENT           *)
    (***********************************************************)
    
  • How do you handle responses back from a device when it comes in multiple lines? The lights spit back three lines when you query their status.

    <E000
    <X002
    <E000

    The line that I need is the middle line.
  • How are you getting commands to your COMM Module?

    I'd normally have:
    data_event[vdvViziaRF]
    {
      command:
    	{
    	  Stack_var char InCommand[10]
    		
    	  InCommand = remove_string(data.text,'-',1)
    		switch (InCommand)
    		{
    		  case 'BRT-': send_string dvViziaRF,"'>N',data.text,'BI'"
    			case 'DIM-': send_string dvViziaRF,"'>N',data.text,'DI'"
    			case 'TOG-': 
    			{
    			  SEND_COMMAND dvViziaRF, "'>?N',data.text" //Status
    				if (status) dvViziaRF, "'>N',data.text,'OF'" 
    				else dvViziaRF, "'>N',data.text,'ON'"
    			}
    		}
    	}
    }
    

    if you need to que the commands, the commands would be parsed easiest if they were added to the que with delimiters ($FE,$FF maybe). Pull the next command out by remove_string looking for $FE$FF. Only parse the que if you find $FE$FF in it.
  • Well, I need to go to training and I think the module is a little over my head for the first project. So I have my first system going in, it is a small one and should be good for educational purposes. I know the client personally and they understand I am learning. This is only to control the Leviton ViziaRF lights. We are using an MVP-5200i (they will be looking to do more after with intercom), NI-700, and the lights over RS-232
    Pretty much want 1 button for each zone that toggles on/off the light and shows the status of the light. I also have another page on the TP for scenes but they are not sure they want to do that yet.
    So this is what I have come up with so far.
    PROGRAM_NAME='ClientXXX'
    (***********************************************************)
    (***********************************************************)
    (*  FILE_LAST_MODIFIED_ON: 04/05/2006  AT: 09:00:25        *)
    (***********************************************************)
    (* System Type : NetLinx                                   *)
    (***********************************************************)
    (* REV HISTORY:                                            *)
    (***********************************************************)
    (*
        $History: $
    *)
    (***********************************************************)
    (*          DEVICE NUMBER DEFINITIONS GO BELOW             *)
    (***********************************************************)
    DEFINE_DEVICE
    
    dvTP = 128:1:0
    dvViziaRF = 5001:1:0
    	(*  Buad = 9600
    	    data bits = 8
    	    stop bit  = 1
                parity    = no parity
                Handshaking = off *)
    vdvTP = 3301:1:0
    vdvViziaRF = 3302:1:0
    
    (***********************************************************)
    (*               CONSTANT DEFINITIONS GO BELOW             *)
    (***********************************************************)
    DEFINE_CONSTANT
    
    INTEGER nTPButtons[] =
        {
    	2,	//Light Zone 2
    	3,	//Light Zone 3
    	4,	//Light Zone 4
    	5,	//Light Zone 5
    	6,	//Light Zone 6
    	7,	//Light Zone 7
    	8,	//Light Zone 8
    	9,	//Light Zone 9
    	10,	//Light Zone 10
    	11,	//Light Zone 11
    	201,	//Scene 1
    	202,	//Scene 2
    	203,	//Scene 3
    	204	//Scene 4
        }
    
    (***********************************************************)
    (*              DATA TYPE DEFINITIONS GO BELOW             *)
    (***********************************************************)
    DEFINE_TYPE
    
    (***********************************************************)
    (*               VARIABLE DEFINITIONS GO BELOW             *)
    (***********************************************************)
    DEFINE_VARIABLE
    
    VOLATILE CHAR cZone	//Stores Selected Light Zone
    cStatus	//Stores Status of Selected Light Zone
    
    (***********************************************************)
    (*               LATCHING DEFINITIONS GO BELOW             *)
    (***********************************************************)
    DEFINE_LATCHING
    
    (***********************************************************)
    (*       MUTUALLY EXCLUSIVE DEFINITIONS GO BELOW           *)
    (***********************************************************)
    DEFINE_MUTUALLY_EXCLUSIVE
    
    (***********************************************************)
    (*        SUBROUTINE/FUNCTION DEFINITIONS GO BELOW         *)
    (***********************************************************)
    (* EXAMPLE: DEFINE_FUNCTION <RETURN_TYPE> <NAME> (<PARAMETERS>) *)
    (* EXAMPLE: DEFINE_CALL '<NAME>' (<PARAMETERS>) *)
       
    (***********************************************************)
    (*                STARTUP CODE GOES BELOW                  *)
    (***********************************************************)
    DEFINE_START
    
    (***********************************************************)
    (*                THE EVENTS GO BELOW                      *)
    (***********************************************************)
    DEFINE_EVENT
    BUTTON_EVENT [dvTP, nTPButtons]
    {
        PUSH:
        {
    	STACK_VAR INTEGER nButtonIndex
    	
    	nButtonIndex = GET_LAST(nTPButtons)
    	cZone = ITOA(nButtonIndex)
    	Switch(cZone)
    	{
    	    Case 201:
    	    {
    	    //scene
    	    }
    	    Case 202:
    	    {
    	    //scene
    	    }
    	    Case 203:
    	    {
    	    //scene
    	    }
    	    Case 204:
    	    {
    	    //scene
    	    }
    	    default: //If it is not a scene
    	    {
    		SEND_COMMAND dvViziaRF, "'>?N', cZone" //gets the status of the Light Zone
    		IF (cStatus = 'OF')
    		{
    		    SEND_COMMAND dvViziaRF, "'>N', cZone, 'ON'"		//Turn Light Zone On
    		    SEND_COMMAND dvTP, "'^ANI-', cZone,',1,2,0'"	//Set TP Button to On
    		}
    		ELSE
    		{
    		SEND_COMMAND dvViziaRF, "'>N', cZone, 'OF'"		//Turn Light Zone Off
    		SEND_COMMAND dvTP, "'^ANI-', cZone,',1,1,0'"		//Set TP Button to Off
    		}
    	    }
    	}
        }
    }
    DATA_EVENT [dvViziaRF]
    {
        STRING:
        {
    	STACK_VAR CHAR cTemp
    	cTemp =ITOA(DATA.TEXT)
    	SWITCH(cTemp)
    	{
    	    CASE 'X002':
    	    {
    		cStatus = 'ON'
    	    }
    	    CASE 'X000':
    	    {
    		cStatus = 'OF'
    	    }
    	}
        }
    }
    (***********************************************************)
    (*            THE ACTUAL PROGRAM GOES BELOW                *)
    (***********************************************************)
    DEFINE_PROGRAM
    
    (***********************************************************)
    (*                     END OF PROGRAM                      *)
    (*        DO NOT PUT ANY CODE BELOW THIS COMMENT           *)
    (***********************************************************)
    
    

    I appreciate all the help, looks like I will be in school in December.
  • jjamesjjames Posts: 2,908
    Be careful on the timing of evaluating states, especially when querying for it. You may want to through in either a WAIT or a WAIT_UNTIL before the evaluation of "cStatus"; then in the DATA_EVENT, you'll make the WAIT_UNTIL true. When doing things like that (asking for a response, then doing something based on the response) think of it like ping-pong. You can't quite hit the ball until it comes back to you, right? Same thing - you can't evaluate until you know the answer.

    So, maybe something like this for the evaluation:
    SEND_STRING dvViziaRF, "'>?N', cZone" //gets the status of the Light Zone
    OFF[nReady]
    WAIT_UNTIL(nReady)
    {
    	IF(cStatus == 'OF')
    	{
    		// do something
    	}
    	
    	ELSE
    	{
    		// do something
    	}
    }
    

    and then in the DATA_EVENT:
    SWITCH(cTemp)
    {
    	CASE 'X002':
    	{
    		cStatus = 'ON'
    		ON[nReady]
    	}
    	CASE 'X000':
    	{
    		cStatus = 'OF'
    		ON[nReady]
    	}
    }
    

    Or, you can simply do a WAIT...
    SEND_STRING dvViziaRF, "'>?N', cZone" //gets the status of the Light Zone
    WAIT 8 // wait 0.8 seconds
    {
    	IF(cStatus == 'OF')
    	{
    		// do something
    	}
    	
    	ELSE
    	{
    		// do something
    	}
    }
    

    And don't forget - SEND_COMMANDs are for virtuals or AMX devices - SEND_STRINGS are for REAL devices that you'll communicate with.
  • jjames wrote: »
    And don't forget - SEND_COMMANDs are for virtuals or AMX devices - SEND_STRINGS are for REAL devices that you'll communicate with.

    Thanks you mentioned this before and it slipped my mind
  • Would you recommend doing this in Define_Start? This is so the TP buttons get updated with the light status at startup.
    DEFINE_START
    cTPCount = 2
    While (cTPCount < 12)
    {
        SEND_STRING dvViziaRF, "'>?N', cTPCount"
        OFF[nReady]
        WAIT_UNTIL(nReady)
        IF (cStatus = 'OF')
        {
    	SEND_STRING dvTP, "'^ANI-', cTPCount,',1,1,0'"	//Set TP Button to OFF
        }
        ELSE
        {
    	SEND_STRING dvTP, "'^ANI-', cZone,',1,2,0'"	//Set TP Button to ON
        }
    }
    
  • jjamesjjames Posts: 2,908
    Mmm - updating the status, yes - like that? Probably not. You'll find a lot of people here tie their button feedback to status in DEFINE_PROGRAM.

    Example:
    [dvTP1,101] = nLiteStatus[1]
    [dvTP1,102] = nLiteStatus[2]
    
    nLiteStatus would be integers, and their values would be set in the DATA_EVENT when parsing the response. On would be 1, off would be 0; this way, each pass of DEFINE_PROGRAM, it gets updated automatically.

    Also, you need brackets around you proposed WAIT_UNTIL if you're going to do an IF/ELSE in it . . . it doesn't fall through.
    WAIT_UNTIL(nReady)
    {
      // put IF/ELSE in here
    }
    

    Another thing, most devices aren't online at DEFINE_START, so you'll probably want to put a WAIT at DEFINE_START before doing anything. Typically, I set variables and trigger an All Off function 15 seconds after startup (DEFINE_START.)
  • Sort of like this then? I have the zone number and the nLiteStatus matching. I went with the actual Zone numbers on the TP buttons seeing they went with non-dimming switches.
    DATA_EVENT [dvViziaRF]
    {
        STRING:
        {
    	STACK_VAR CHAR cTemp
    	cTemp =ITOA(DATA.TEXT)
    	SWITCH(cTemp)
    	{
    	    CASE 'X002':
    	    {
    		cStatus = 'ON'
    		ON[nReady]
    		nLiteStatus[cZone] = 1
    	    }
    	    CASE 'X000':
    	    {
    		cStatus = 'OF'
    		ON[nReady]
    		nLiteStatus[cZone] = 0
    	    }
    	}
        }
    }
    
    (***********************************************************)
    (*            THE ACTUAL PROGRAM GOES BELOW                *)
    (***********************************************************)
    DEFINE_PROGRAM
    [dvTP, 2] = nLiteStatus[2]
    [dvTP, 3] = nLiteStatus[3]
    [dvTP, 4] = nLiteStatus[4]
    [dvTP, 5] = nLiteStatus[5]
    [dvTP, 6] = nLiteStatus[6]
    [dvTP, 7] = nLiteStatus[7]
    [dvTP, 8] = nLiteStatus[8]
    [dvTP, 9] = nLiteStatus[9]
    [dvTP, 10] = nLiteStatus[10]
    [dvTP, 11] = nLiteStatus[11]
    
  • jjamesjjames Posts: 2,908
    Yup! Getting the idea. :D

    Something I noticed though in the DATA_EVENT.

    cTemp will only be one character, and DATA.TEXT is not an integer - no ITOA. There's gotta be more to the parsing, yes? Don't forget to assign cZone or are you doing that in the button press?
  • More like this then.
     STRING:
        {
    	STACK_VAR CHAR cTemp[4]    //4 characters
    	cTemp =(DATA.TEXT)               //Data.text is in X###
    	SWITCH(cTemp)
    

    Also yes the cZone is being set on the Button Press
  • jjamesjjames Posts: 2,908
    Yup, that should work. It's up to you, but you can remove the parenthesis and just make it cTemp = DATA.TEXT, no need for them.

    Also, since the zone is probably an integer, you may want to prefix it with an "n" and not a "c". Makes me think cZone is a character and not an integer, but know that's not possible when you put it in the array. Now we're getting picky. :D

    Number one goal I feel in programming a system for a client, is to make it work. After that, it's efficiency. Get it to work, then clean up the code.
  • The only question in my head right now is with the Define_Program, the zone is being set in the Button_Event, how would it work that the Define Program knows what zone it is?
    DEFINE_EVENT
    BUTTON_EVENT [dvTP, nTPButtons]
    {
        PUSH:
        {
    	STACK_VAR INTEGER nButtonIndex
    	
    	nButtonIndex = GET_LAST(nTPButtons)
    	cZone = ITOA(nButtonIndex)
    	Switch(cZone)
    	{
    	    Case 201:
    	    {
    	    //scene
    	    }
    	    Case 202:
    	    {
    	    //scene
    	    }
    	    Case 203:
    	    {
    	    //scene
    	    }
    	    Case 204:
    	    {
    	    //scene
    	    }
    	    default: //If it is not a scene
    	    {
    		SEND_STRING dvViziaRF, "'>?N', cZone" //gets the status of the Light Zone
    		OFF[nReady]
    		WAIT_UNTIL(nReady)
    		{
    		    IF (cStatus = 'OF')
    		    {
    			SEND_STRING dvViziaRF, "'>N', cZone, 'ON'"		//Turn Light Zone On
    			SEND_STRING dvViziaRF, '>UP'				//Updates all Vizia Controllers
    		    }
    		    ELSE
    		    {
    			SEND_STRING dvViziaRF, "'>N', cZone, 'OF'"		//Turn Light Zone Off
    			SEND_STRING dvViziaRF, '>UP'				//Updates all Vizia Controllers
    		    }
    		}
    	    }
    	}
        }
    }
    DATA_EVENT [dvViziaRF]
    {
        STRING:
        {
    	STACK_VAR CHAR cTemp[4]
    	cTemp = (DATA.TEXT)
    	SWITCH(cTemp)
    	{
    	    CASE 'X002':
    	    {
    		cStatus = 'ON'
    		ON[nReady]
    		nLiteStatus[cZone] = 1
    	    }
    	    CASE 'X000':
    	    {
    		cStatus = 'OF'
    		ON[nReady]
    		nLiteStatus[cZone] = 0
    	    }
    	}
        }
    }
    
    (***********************************************************)
    (*            THE ACTUAL PROGRAM GOES BELOW                *)
    (***********************************************************)
    DEFINE_PROGRAM
    [dvTP, 2] = nLiteStatus[2]
    [dvTP, 3] = nLiteStatus[3]
    [dvTP, 4] = nLiteStatus[4]
    [dvTP, 5] = nLiteStatus[5]
    [dvTP, 6] = nLiteStatus[6]
    [dvTP, 7] = nLiteStatus[7]
    [dvTP, 8] = nLiteStatus[8]
    [dvTP, 9] = nLiteStatus[9]
    [dvTP, 10] = nLiteStatus[10]
    [dvTP, 11] = nLiteStatus[11]
    

    I was thinking I need a TO or While Statement that sets the zone like this.
    DEFINE_PROGRAM
    nCount = 2
    WHILE (nCount < 12)
    {
            cZone = nCount
            [dvTP, nCount] = nLiteStatus[nCount]
    }
    
  • a_riot42a_riot42 Posts: 1,624
    jjames wrote: »
    Get it to work, then clean up the code.

    Interesting perspective. I tend to go the other way. Making it work is a far bigger challenge when your code is messy and unorganized. Often there isn't a chance to do any cleanup and the code stays that way.
    Paul
  • a_riot42 wrote: »
    Interesting perspective. I tend to go the other way. Making it work is a far bigger challenge when your code is messy and unorganized. Often there isn't a chance to do any cleanup and the code stays that way.
    Paul

    Seconded. Usually I write something, get it working and implement it, then read something here and learn a better way I could have done it. Going back to "correct" already working code, seems to be more work than its worth. Just have to remember to do it the correct way the next time.
  • I believe he is mainly trying to tell me that once I figure out what I am doing I will learn how to do things more efficient then I originally did. But until i fully understand how it works I would not be able to improve.

    I am use to trying to condense my programs, if i can do in 2 lines what i can do in 10 then do it.
  • I am use to trying to condense my programs, if i can do in 2 lines what i can do in 10 then do it.

    Word to that (or whatever slang for "I agree" is popular nowadays). One day, I would really like to post my very first programming job. I didn't know how to use arrays or anything. I did everything line by line. Really horrible. Then I went to class, joined this forum, and increased my AMX Jedi skills. Still have a long ways to go though. I would love so much to go back to that first job and "fix" it. But it is a conference room in Iraq, so I really doubt they would pay for my plane tickets just to go over there and make it better.

    Now that I am thinking about that program, it makes me laugh. Not only did I not use any arrays, but I did not know how to properly manipulate strings. So, I hard coded everything. All of the perceived feedback to the touch panel, was written into the code. Like when they opened the mics on the Tandberg, the TP would indicate the mics were on even if the Tandberg was powered off. And the TP would probably win an award for AMX's worst designed touch panel. It all worked and met their requirements, but now that I am wiser and know better, I am really embarrassed by it.
  • jjamesjjames Posts: 2,908
    Right, what I'm saying is - get it working for the client. That's number one. I think all of us can agree that in order to be a successful company / programmer / etc., we need to deliver what we promise in a timely manner. I don't always recommend going back and "cleaning" up the messy code for old projects, but as you learn, you'll be able to clean up your newer code. That's all I meant. My boss' code: unbelievably horrible - from a coding standpoint. A hundred different BUTTON_EVENTs for a hundred different buttons, when you only needed 10 BUTTON_EVENTs - but guess what? It worked. Would I go back and rewrite his stuff? Absolutely not unless we were doing a HUGE upgrade on the house - which we have. I think I'm getting off topic.

    Anyway, as to the DEFINE_PROGRAM question. If [dvTP,2] is always for lighting zone number 2, and nLiteStatus[2] is updated in the DATA_EVENT then what you had originally will work, no need for the loop.

    And, I just looked further into your code . . . okay. cZone looks like it is a character, in which case, you cannot use it to designate a position in an array. A char "1" would be a decimal 49, which is probably too big for the array, so you'd be getting "runtime errors." You need a new variable, like nZone, which would be the equivalent to nButtonIndex, but global so that it could be referenced elsewhere in code. Unless of course, you did a ATOI on cZone every time you needed to get the decimal version of the zone - which, would not be recommended.
  • Ok I went through this and seeing how I have played with the lighting through hyperterminal I decided to change up how I was doing this. So here is the code I have right now. The AMX equipment should be in this week so I am just trying to get a head any insight is very welcome and appreciated. Again this is my first system.
    PROGRAM_NAME='ClientXXX'
    (***********************************************************)
    (***********************************************************)
    (*  FILE_LAST_MODIFIED_ON: 11/05/2008  AT: 15:36:28        *)
    (***********************************************************)
    (* System Type : NetLinx                                   *)
    (***********************************************************)
    (* REV HISTORY:                                            *)
    (***********************************************************)
    (*
        $History: $
    *)
    (***********************************************************)
    (*          DEVICE NUMBER DEFINITIONS GO BELOW             *)
    (***********************************************************)
    DEFINE_DEVICE
    
    dvTP = 128:1:0
    dvViziaRF = 5001:1:0
    	(*  Buad = 9600
    	    data bits = 8
    	    stop bit  = 1
                parity    = no parity
                Handshaking = off *)
    vdvTP = 3301:1:0
    vdvViziaRF = 3302:1:0
    
    (***********************************************************)
    (*               CONSTANT DEFINITIONS GO BELOW             *)
    (***********************************************************)
    DEFINE_CONSTANT
    
    INTEGER nTPButtons[] =
        {
    	// Individual Nodes
    	101,	//Node 1
    	102,	//Node 2
    	103,	//Node 3
    	104,	//Node 4
    	105,	//Node 5
    	106,	//Node 6
    	107,	//Node 7
    	108,	//Node 8
    	109,	//Node 9
    	110,	//Node 10
    	111,	//Node 11
    	112,	//Node 12
    	113,	//Node 13
    	114,	//Node 14
    	115,	//Node 15
    	116,	//Node 16
    	117,	//Node 17
    	118,	//Node 18
    	119,	//Node 19
    	120,	//Node 20
    	// Groups - A set of switches/Dimmers to behave as one node
    	201,	//Group 1
    	202,	//Group 2
    	203,	//Group 3
    	204,	//Group 4
    	205,	//Group 5
    	206,	//Group 6
    	207,	//Group 7
    	208,	//Group 8
    	209,	//Group 9
    	210,	//Group 10
    	//Scenes 
    	301,	//Scene 1
    	302,	//Scene 2
    	303,	//Scene 3
    	304,	//Scene 4
    	305,	//Scene 5
    	306,	//Scene 6
    	307,	//Scene 7
    	308,	//Scene 8
    	309,	//Scene 9
    	310	//Scene 10
        }
    
    (***********************************************************)
    (*               VARIABLE DEFINITIONS GO BELOW             *)
    (***********************************************************)
    DEFINE_VARIABLE
    
    VOLATILE CHAR cType				//Stores Selected Node Type
    VOLATILE CHAR cTypeData 			//Stores the type of device on feedback
    VOLATILE CHAR cNode				//Stores Selected Light Node
    VOLATILE CHAR cGroup				//Stores Selected Light Group
    VOLATILE CHAR cScene				//Stores Selected Light Scene
    VOLATILE CHAR cStatus				//Stores Status of Selected Light Zone
    VOLATILE CHAR cMessage				//Stores Light Node/Group/Scene Level error information
    INTEGER nReady					//Flag for waiting for response from Lights
    INTEGER nLiteStatus[400] 			//Stores Light Status for feedback on TP
    INTEGER nNode					//Stores Selected Light Node for Array position
    INTEGER nGroup					//Stores Selected Light Group for Array position
    INTEGER nScene					//Stores Selected Light Scene for Array position
    INTEGER nType					//Stores Selected Light Type for Array Position
    
    (***********************************************************)
    (*                STARTUP CODE GOES BELOW                  *)
    (***********************************************************)
    DEFINE_START
    
    (***********************************************************)
    (*                THE EVENTS GO BELOW                      *)
    (***********************************************************)
    DEFINE_EVENT
    BUTTON_EVENT [dvTP, nTPButtons]
    {
        PUSH:
        {
    	STACK_VAR INTEGER nButtonIndex
    	
    	nButtonIndex = GET_LAST(nTPButtons)
    	nType = nButtonIndex
    	IF (nType < 200)
    	{
    	    cType = 'Node'
    	    cNode = ITOA(nButtonIndex)
    	    SEND_STRING dvViziaRF, "'>?N', cNode" 			//gets the status of the Light Zone
    	    OFF[nReady]
    	    WAIT_UNTIL(nReady)
    	    {
    		IF (cStatus = 'OF')
    		{
    		    SEND_STRING dvViziaRF, "'>N', cNode, 'ON'"		//Turn Light Zone On
    		    SEND_STRING dvViziaRF, '>UP'			//Updates all Vizia Controllers
    		}
    		ELSE
    		{
    		    SEND_STRING dvViziaRF, "'>N', cNode, 'OF'"		//Turn Light Zone Off
    		    SEND_STRING dvViziaRF, '>UP'			//Updates all Vizia Controllers
    		}
    	    }
    	}
    	ELSE IF (nType < 300)
    	{
    	    cType = 'Group'
    	    cGroup = ITOA(nButtonIndex)
    	    SEND_STRING dvViziaRF, "'>?GR', cGroup"			//Gets the status of the Light Group
    	    OFF[nReady]
    	    WAIT_UNTIL(nReady)
    	    {
    		IF (cStatus = 'OF')
    		{
    		    SEND_STRING dvViziaRF, "'>GR', cGroup, 'ON'"	//Turn Group On
    		    SEND_STRING dvViziaRF, 'UP'				//Updates all Vizia Controllers
    		}
    		ELSE
    		{
    		    SEND_STRING dvViziaRF, "'>GR', cGroup, 'OF'"	//Turn Group Off
    		    SEND_STRING dvViziaRF, 'UP'				//Updates all Vizia Controllers
    		}
    	    }
    	}
    	ELSE IF (nType < 400)
    	{
    	    cType = 'Scene'
    	    cScene = ITOA(nButtonIndex)
    	    SEND_STRING dvViziaRF, "'>?S', cScene"			//Gets the status of the Light Scene
    	    OFF[nReady]
    	    WAIT_UNTIL(nReady)
    	    {
    		IF (cStatus = 'OF')
    		{
    		    SEND_STRING dvViziaRF, "'>S', cScene, 'ON'"		//Turn Scene On
    		    SEND_STRING dvViziaRF, 'UP'				//Update all Vizia Controllers
    		}
    		ELSE
    		    SEND_STRING dvViziaRF, "'>S', cScene, 'OF'"		//Turn Scene Off
    		    SEND_STRING dvViziaRF, 'UP'				//Update all Vizia Controllers
    		}
    	    }
    	}
        }
    
    DATA_EVENT [dvViziaRF]
    {
        ONLINE:
        {
    	SEND_STRING dvViziaRF , 'SET BAUD 9600,N,8,1'
        }
        STRING:
        {
    	STACK_VAR CHAR cTemp[17]				// Max 17 characters in the received data from Vizia RS232 module
    	cTemp = (DATA.TEXT)
    	IF (length_string(cTemp) == 5)				//If data is 5 characters it is an error or infomation
    	{
    	    cTypeData = 'Info'
    	    cMessage = MID_STRING(cTemp, 2, 4)
    	}
    	ELSE IF (length_string(cTemp) == 9)			//If data is 9 characters it is a level or status
    	{
    	    cTypeData = 'Status'
    	    cMessage = MID_STRING(cTemp, 6, 4)
    	    IF (find_string(cTemp, 'N', 1) == 1)		//If this is a switch or dimmer
    	    {
    		cNode = "'1', MID_STRING(cTemp, 4, 2)"		//Strip the >N0 and add 1 to the beginning for TP Node Button Number
    		nNode = ATOI(cNode)
    	    }
    	    ELSE IF (find_string(cTemp, 'G', 1) == 1)
    	    {
    		cNode = "'2', MID_STRING(cTemp, 4, 2)"		//Strip the >G0 and add 2 to the beginning for TP Group Button Number
    		nNode = ATOI(cNode)
    	    }
    	    ELSE IF (find_string(cTemp, 'S', 1) == 1)
    	    {
    		cNode = "'3', MID_STRING(cTemp, 4, 2)"		//Strip the >S0 and add 1 to the beginning for TP Scene Button Number
    		nNode = ATOI(cNode)
    	    }
    	}
    	SWITCH(cMessage)
    	{
    	    CASE 'L255':
    	    {
    		cStatus = 'ON'
    		ON[nReady]
    		nLiteStatus[nNode] = 1
    	    }
    	    CASE 'L000':
    	    {
    		cStatus = 'OF'
    		ON[nReady]
    		nLiteStatus[nNode] = 0
    	    }
    	    // RF Transmission Messages
    	    CASE 'X000':					//No RF Transmission Error
    	    {
    		ON[nReady]
    	    }
    	    CASE 'X002':					//RF Transmission Error
    	    {
    		ON[nReady]
    	    }
    	    // Errors sent from the Vizia RS-232 Module
    	    CASE 'E000':					//no error
    	    {
    		ON[nReady]
    	    }
    	    CASE 'E001':					//wrong start of the string symbol
    	    {
    		ON[nReady]
    	    }
    	    CASE 'E002':					//Input buffer overflow.
    	    {
    		ON[nReady]
    	    }
    	    CASE 'E003':					//Can not start RF transmission. All buffers are taken.
    	    {
    		ON[nReady]
    	    }
    	    CASE 'E004':					//Can not start RF transmission because previous one has not finished.
    	    {
    		ON[nReady]
    	    }
    	    CASE 'E005':					//Unrecognized command
    	    {
    		ON[nReady]
    	    }
    	    CASE 'E006':					//Attempt to send the new buffer over RS232 before previous one had been processed.
    	    {
    		ON[nReady]
    	    }
    	    CASE 'E007':					//The send Message does not have data fields specified.
    	    {
    		ON[nReady]
    	    }
    	    CASE 'E008':					//Can not stop SUC mode. Node is SUC.
    	    {
    		ON[nReady]
    	    }
    	    CASE 'E009':					//EERPOM is busy, can?t store group information
    	    {
    		ON[nReady]
    	    }
    	    CASE 'E010':					//No devices with specified properties have been found
    	    {
    		ON[nReady]
    	    }
    	}
        }
    }
    
    (***********************************************************)
    (*            THE ACTUAL PROGRAM GOES BELOW                *)
    (***********************************************************)
    DEFINE_PROGRAM
    [dvTP, 101] = nLiteStatus[101]
    [dvTP, 102] = nLiteStatus[102]
    [dvTP, 103] = nLiteStatus[103]
    [dvTP, 104] = nLiteStatus[104]
    [dvTP, 105] = nLiteStatus[105]
    [dvTP, 106] = nLiteStatus[106]
    [dvTP, 107] = nLiteStatus[107]
    [dvTP, 108] = nLiteStatus[108]
    [dvTP, 109] = nLiteStatus[109]
    [dvTP, 110] = nLiteStatus[110]
    [dvTP, 111] = nLiteStatus[111]
    [dvTP, 112] = nLiteStatus[112]
    [dvTP, 113] = nLiteStatus[113]
    [dvTP, 114] = nLiteStatus[114]
    [dvTP, 115] = nLiteStatus[115]
    [dvTP, 116] = nLiteStatus[116]
    [dvTP, 117] = nLiteStatus[117]
    [dvTP, 118] = nLiteStatus[118]
    [dvTP, 119] = nLiteStatus[119]
    [dvTP, 120] = nLiteStatus[120]
    [dvTP, 201] = nLiteStatus[201]
    [dvTP, 202] = nLiteStatus[202]
    [dvTP, 203] = nLiteStatus[203]
    [dvTP, 204] = nLiteStatus[204]
    [dvTP, 205] = nLiteStatus[205]
    [dvTP, 206] = nLiteStatus[206]
    [dvTP, 207] = nLiteStatus[207]
    [dvTP, 208] = nLiteStatus[208]
    [dvTP, 209] = nLiteStatus[209]
    [dvTP, 210] = nLiteStatus[210]
    [dvTP, 301] = nLiteStatus[301]
    [dvTP, 302] = nLiteStatus[302]
    [dvTP, 303] = nLiteStatus[303]
    [dvTP, 304] = nLiteStatus[304]
    [dvTP, 305] = nLiteStatus[305]
    [dvTP, 306] = nLiteStatus[306]
    [dvTP, 307] = nLiteStatus[307]
    [dvTP, 308] = nLiteStatus[308]
    [dvTP, 309] = nLiteStatus[309]
    [dvTP, 310] = nLiteStatus[310]
    
    (***********************************************************)
    (*                     END OF PROGRAM                      *)
    (*        DO NOT PUT ANY CODE BELOW THIS COMMENT           *)
    (***********************************************************)
    

    I added some error messages the Lighting can kick back but I have not done anything with them yet, I have not decided if I want the error to send a message to the TP or not.
Sign In or Register to comment.