Home AMX User Forum NetLinx Studio

Button Events

As some of you who have seen my previous post are aware, I'm learning to program in Netlinx.

I used what I have learned in CP131 on Harman University and made a program and transferred it to a NX3200.

After a few adjustments, the program worked as I intended. Now that I have learned more and found myself comfortable with the idea of utilizing variables I want to update the code to run cleaner and with more dependable feedback.

I've reworked the button events and feedback for the new version of the button events. I'm hoping someone with more experience than myself would be so kind as to look at my work and let me know if it will do what I expect it to do.

I have commented next to each line in the button events and feedback statements my intention for the effect of that line.

Thank you!


[/SIZE](***********************************************************)
(***********************************************************)
(*  FILE_LAST_MODIFIED_ON: 04/05/2006  AT: 09:00:25        *)
(***********************************************************)
(* System Type : NetLinx                                   *)
(***********************************************************)
(* REV HISTORY:                                            *)
(***********************************************************)
(*
    $History: $
*)

(***********************************************************)
(*          DEVICE NUMBER DEFINITIONS GO BELOW             *)
(***********************************************************)
DEFINE_DEVICE

// NX3200 Controller - In main system rack

dvAUDIOSW       =5001:2:0//PrecisDSPSW @ Serial#2 on NX3200
dvIR_GRT_EQPMT  =5001:11:0//NX3200 IR port to Great Room

// Touch Panel - Modero MST-1001 In Great Room

dvTP_SOURCEio   =10001:1:0//Modero MST-1001 TP Audio IN_OUT select
dvTP_GRT_EQPMT  =10001:2:0//Great Room Equipment - Marantz RCVR, LG TV, LG DVD and Motorola Cable box

(***********************************************************)
(*               CONSTANT DEFINITIONS GO BELOW             *)
(***********************************************************)
DEFINE_CONSTANT

long tl_AUDxStatus =1    //this is the timeline ID for audio switch status feedback timeline

(***********************************************************)
(*              DATA TYPE DEFINITIONS GO BELOW             *)
(***********************************************************)
DEFINE_TYPE

(***********************************************************)
(*               VARIABLE DEFINITIONS GO BELOW             *)
(***********************************************************)
DEFINE_VARIABLE

//Variable to track audio switch zone output connection status

volatile integer nAUDx_Global_Out    //Audio switch global output connnection status variable
volatile integer nAUDx_Out1          //Audio switch output 1 connection status variable
volatile long l_AUDxStatus[]=        //This is the array of times for audio switch status feedback timeline
{
    1000        //1 second = 1000 milliseconds
}
(***********************************************************)
(*               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

//Feedback timeline for Audio Zone Switch connection status

timeline_create(tl_AUDxStatus,l_AUDxStatus,length_array(l_AUDxStatus),timeline_absolute,timeline_repeat)//creation of timeline

//5 parameters within set of parenthesis
//First 3 parameters are:
//1 - Timeline ID - This is defined in the "Define_Constant" section and must be unique
//2 - Array of times - This is defined in "Define_Variable" section and is a volatile long in this instance
//3 - Number of times provided in array (keyword "length_array" followed by array in set of parenthesis)
//parameters 4 and 5 are:
//4 - specifies times in array to be considered absolute times from the start of the timeline or relative times
//from one time value to the next
//5 - specifies whether timeline is to run once or to continually repeat
//(timeline ID, array of times, number of times provided in array,(array variable long integer), timeline keyword, timeline keyword)
(***********************************************************)
(*                THE EVENTS GO BELOW                      *)
(***********************************************************)
DEFINE_EVENT

//Set dvIR_GRT_EQPMT mode to IR and turn on IR carrier on power up

data_event[dvIR_GRT_EQPMT]
{
    online:
    {
          send_command dvIR_GRT_EQPMT,"'SET MODE IR'"
          send_command dvIR_GRT_EQPMT,"'CARON'"
    }
}

//Disconnect all audio switch outputs on power up

data_event[dvAUDIOSW]
{
    online:
    {
          send_string dvAUDIOSW,'DL2O1:18T'
          nAUDx_Global_Out =0
    }
}

//TP Button to disconnect all audio switch outputs

button_event[dvTP_SOURCEio,20]
{
    push:
    {
          send_string dvAUDIOSW,'DL2O1:18T' //Disconnects all outputs on audio switch
          nAUDx_Global_Out =0
    }
}

//Great Room Power All Equipment - programmed on port 1 to avoid conflict with button 0 on port 2
//which controls all Great Room equipment

button_event[dvTP_SOURCEio,10]
{
    push:
    {
    pulse[dvIR_GRT_EQPMT,2] //Marantz Power
    wait 10
    {
        pulse[dvIR_GRT_EQPMT,1] //TV Power
        wait 10
        {
          //pulse[dvIR_GRT_EQPMT,10] //Cable Power - leave commented out until fav chan buttons are written
          //wait 10
        {
              pulse[dvIR_GRT_EQPMT,41] //DVD Power
        }
        }
    }    

    }
}

//Great Room Controls - any button pressed on dvTP_GRT_EQPMT will output corresponding channel
//IR signal in Great Room IR file mapped to dvIR_GRT_EQPMT
//dvTP_GRT_EQPMT is port 2

button_event[dvTP_GRT_EQPMT,0]
{
    push:
    {
          to[dvIR_GRT_EQPMT,button.input.channel]//emits IR code channel on IR file when corresponding TP channel is pushed
          to[dvTP_GRT_EQPMT,button.input.channel]//provides channel feedback
    }
}

//dvTP_SOURCEio is port 1
//IN 1 = Sonos #1 | OUT 1 = [B][COLOR=#0000FF]Game/Fish Zone[/COLOR][/B]

button_event[dvTP_SOURCEio,11]//Make or break connection of In_1 to Out_1
{
    push:
    {
          if(nAUDx_Out1==2)                 //OUT 1 variable indicates OUT 1 is currently connected to IN 2
          {                                 //
          send_string dvAUDIOSW,'CL2I1O1T'  //Connect IN_1 to OUT_1 = CL2I1O1T
          nAUDx_Out1=1                      //Change OUT 1 variable to indicate OUT 1 is connected to IN 1
          }
          else if(nAUDx_Out1==1)            //OUT 1 variable indicates OUT 1 is connected to IN 1
          {
          send_string dvAUDIOSW,'DL2O1T'    //Disconnect OUT 1 = DL2O1T
          nAUDx_Out1=0                      //Change OUT 1 variable to indicate OUT 1 is not connected
          nAUDx_Global_Out--                //Total connected outputs variable is reduced by 1
          }
          else                              //OUT 1 variable indicates OUT 1 it is not connected (nAUDx_Out1=0)
          {
          send_string dvAUDIOSW,'CL2I1O1T'  //Connect IN_1 to OUT_1 = CL2I1O1T
          nAUDx_Out1=1                      //Change OUT 1 variable to indicate OUT 1 is connected to IN 1
          nAUDx_Global_Out++                //Total connected outputs variable is increased by 1
          }
    }
}

//IN 2 = Sonos #2 | OUT 1 = [B][COLOR=#0000FF]Game/Fish Zone[/COLOR][/B]

button_event[dvTP_SOURCEio,12]//Make or break connection of In_2 to Out_1
{
    push:
    {
          if(nAUDx_Out1==1)                 //OUT 1 variable indicates OUT 1 is currently connected to IN 1
          {                                 //
          send_string dvAUDIOSW,'CL2I2O1T'  //Connect IN_2 to OUT_1 = CL2I2O1T
          nAUDx_Out1=2                      //Change OUT 1 variable to indicate OUT 1 is connected to IN 2
          }
          else if(nAUDx_Out1==2)            //OUT 1 variable indicates OUT 1 is connected to IN 2
          {
          send_string dvAUDIOSW,'DL2O1T'    //Disconnect OUT 1 = DL2O1T
          nAUDx_Out1=0                      //Change OUT 1 variable to indicate OUT 1 is not connected
          nAUDx_Global_Out--                //Total connected outputs variable is reduced by 1
          }
          else                              //OUT 1 variable indicates OUT 1 it is not connected (nAUDx_Out1=0)
          {
[SIZE=12px]          send_string dvAUDIOSW,'CL2I1O1T'  //Connect IN_1 to OUT_1 = CL2I1O1T
          nAUDx_Out1=2                      //Change OUT 1 variable to indicate OUT 1 is connected to IN 2
          nAUDx_Global_Out++                //Total connected outputs variable is increased by 1[/SIZE]
          }
    }

}

//IN 1 = Sonos #1 | OUT 2 = [B][COLOR=#FF8C00]Basement TV Zone[/COLOR][/B]

button_event[dvTP_SOURCEio,13]//Make or break connection of In_1 to Out_2
{
    push:
    {
          if([dvTP_SOURCEio,13])          //If CH13 is in ON state this condition is "True"
          {                               //I want this sequence to occure if CH11 is pushed while in ON state
          send_string dvAUDIOSW,'DL2O2T'; //disconnect OUT_2 = DL2O2T
          off[dvTP_SOURCEio,3];           //CH3 button to off state
          off[dvTP_SOURCEio,13];          //CH13 button to off state
          }                    
          else                            //Else CH13 is in OFF state or "False"
          {                               //I want this sequence to occur if CH13 is pushed while in OFF state
          send_string dvAUDIOSW,'DL2O2T'  //disconnect OUT_2 = DL2O2T = D(disconnect)L2(audio)O2(out2)T(execute)
          off[dvTP_SOURCEio,4];           //CH4 button to off state
          off[dvTP_SOURCEio,14];          //CH14 button to off state
          send_string dvAUDIOSW,'CL2I1O2T'//connect IN_1 to OUT_2 = CL2I1O1T
          on[dvTP_SOURCEio,3];            //CH3 button to on state
          on[dvTP_SOURCEio,13];           //CH13 button to on state
          }
    }
}

//IN 2 = Sonos #2 | OUT 2 = [COLOR=#FF8C00][B]Basement TV Zone[/B][/COLOR]

button_event[dvTP_SOURCEio,14]//Make or break connection of In_2 to Out_2
{
    push:
    {
          if([dvTP_SOURCEio,14])    
          {            
          send_string dvAUDIOSW,'DL2O2T';
          off[dvTP_SOURCEio,4];    
          off[dvTP_SOURCEio,14];
          }        
          else            
          {            
          send_string dvAUDIOSW,'DL2O2T'
          off[dvTP_SOURCEio,3];    
          off[dvTP_SOURCEio,13];    
          send_string dvAUDIOSW,'CL2I2O2T'
          on[dvTP_SOURCEio,4];    
          on[dvTP_SOURCEio,14];
          }
    }
}

//Audio Zone Switch connection status feedback timeline
//Feedback timelines should be placed at the bottom of the events section

timeline_event[tl_AUDxStatus]
{
    [dvTP_SOURCEio,1]      = (nAUDx_Out1==1)       //I want chan 1 to be in on state when variable =1
    [dvTP_SOURCEio,11]     = (nAUDx_Out1==1)       //I want chan 11 to be in on state when variable =1
    [dvTP_SOURCEio,2]      = (nAUDx_Out1==2)       //I want chan 2 to be in on state when variable =2
    [dvTP_SOURCEio,12]     = (nAUDx_Out1==2)       //I want chan 12 to be in on state when variable =2
    [dvTP_SOURCEio,21]     = (nAUDx_Global_Out)    //I want chan 21 to be in on state when variable =0
}
(*****************************************************************)
(*                                                               *)
(*                      !!!! WARNING !!!!                        *)
(*                                                               *)
(* Due to differences in the underlying architecture of the      *)
(* X-Series masters, changing variables in the DEFINE_PROGRAM    *)
(* section of code can negatively impact program performance.    *)
(*                                                               *)
(* See ?Differences in DEFINE_PROGRAM Program Execution? section *)
(* of the NX-Series Controllers WebConsole & Programming Guide   *)
(* for additional and alternate coding methodologies.            *)
(*****************************************************************)

DEFINE_PROGRAM

(*****************************************************************)
(*                       END OF PROGRAM                          *)
(*                                                               *)
(*         !!!  DO NOT PUT ANY CODE BELOW THIS COMMENT  !!!      *)
(*                                                               *)
(*****************************************************************)

[SIZE=8px]

Edit - removed attached image of code - resubmitted code with copy/paste and wrapped in [code] tags. Added below text.

When I copy and pasted the code into the [code] tags the spacing got wrecked so I straightened it up. Not sure if I should've fixed it or not after realizing that someone might copy from here and paste into Netlinx and it will all be wrecked going in there. If it is better to not fix spacing after pasting into [code] I will gladly redo.

This system has 15 zone outputs and 2 source inputs.

I wrote a pair of button events (one for each input source) for each of the 15 outputs (zones). I only included button events for 2 outputs (zones) in this post.
The remaining 13 outputs (zones) button events is all that I have omitted from the code I posted.

The pair of button events //commented as ....Basement TV Zone is the current version that is working in the system. Fake Feedback.

The pair of button events above them, //commented as .....Game/Fish Zone is the "new version" that I want to implement using variables to track status and provide feedback. Better Fake Feedback.

My intention is to duplicate the new version pair of button events and define a variable for each output to provide connection feedback for each zone. The global variable is to be included in each zone button event to provide feedback regarding any zone being connected.

Some of you may have your hair catch on fire or have a great laugh or both, but thank you for taking the time to look it over!

Comments

  • a_riot42a_riot42 Posts: 1,624
    Just a couple suggestions.

    First post all the relevant code and put it in [code] blocks. Don't post an image of code.

    If you are tracking the state of a switcher, its probably best to update the state only when the switcher sends feedback. Just because you sent a command doesn't mean the command got sent and device updated, so if you update your own variables based on your own commands, things can get out of sync. You are assuming the state changed just because you sent the command. I would have an event that listens to the switcher feedback and update your variables accordingly based on that, then update your touch panels based on that. That way you don't even need the timeline_event. That way your feedback is always true feedback, not faked.

    While legal, use the double equals in if guards rather than the single equals. IE if (i == 1) instead of if (i=1)

    Be careful decrementing a variable without checking its value. If you declared it as an integer, and decrement it when its value is 0, then it will take on a value of 65535 since it will rollover like an odometer.

    Use arrays in button event headers, and then use get_last to get the value. You can often collapse many button events into one event that way. Makes debugging much easier, and requires far less code. I'd show you what I mean, but I can't copy/paste your code since its an image.

    Learn how to indent code properly.
    Paul

  • Awesome, thank you man! This is exactly the type of response I was hoping for.
    Just a couple suggestions.

    First post all the relevant code and put it in [code] blocks. Don't post an image of code.

    I apologize for posting an image of the code. I overlooked this in the FAQ. Fixed.
    If you are tracking the state of a switcher, its probably best to update the state only when the switcher sends feedback. Just because you sent a command doesn't mean the command got sent and device updated, so if you update your own variables based on your own commands, things can get out of sync. You are assuming the state changed just because you sent the command. I would have an event that listens to the switcher feedback and update your variables accordingly based on that, then update your touch panels based on that. That way you don't even need the timeline_event. That way your feedback is always true feedback, not faked.

    Fake feedback, is not my first choice. This version of fake feedback is better than my previous version of fake feedback though, lol. I have the documentation on the switch, and I know what it sends when a switch occurs. I don't yet understand how to reference feedback from the switch in my code.
    While legal, use the double equals in if guards rather than the single equals. IE if (i == 1) instead of if (i=1)

    I will change this right away
    Be careful decrementing a variable without checking its value. If you declared it as an integer, and decrement it when its value is 0, then it will take on a value of 65535 since it will rollover like an odometer.

    Sound advice. I intend for this variable to always and only be changed when an output (zone) is connected ++ or disconnected --. In an effort to prevent things from getting out of sync I have a "disconnect all outputs (zones)" button and a data_event {online}, both of which change the value of this variable to zero and send the appropriate disconnect string to the switch.

    My current understanding is going to produce low grade code and unorthodox approaches to making things do what I intend for them to do. As I learn more I will continue to update and improve this code.
    Use arrays in button event headers, and then use get_last to get the value. You can often collapse many button events into one event that way. Makes debugging much easier, and requires far less code. I'd show you what I mean, but I can't copy/paste your code since its an image.

    I do not have a clear understanding on how and when to use arrays. I do know from the lesson on arrays, that they have 3 components. Dimension, Index and Element.

    The best way for me to learn new things is to do it and actually see the results in action. I can memorize and repeat the new information, but that doesn't get me very far. If you can demonstrate how this is done it would help me a great deal in utilizing arrays.
    Learn how to indent code properly.

    I've not seen a guide or learned any standard regarding code indentation. Is there such a guide? Is it just to indent for each new set of braces?

    Something I'm interested in avoiding is having something done for me and not understanding how it is accomplished myself. Much like driving in unfamiliar territory using a navigation app. You'll get where you want to go but you'll likely not be sure exactly how you got there or how to get back without using the app again.

    Thank you again, I can't tell you how much I appreciate the suggestions you provided in your response!
  • rogerroger Posts: 4

    I've not seen a guide or learned any standard regarding code indention. Is there such a guide?

    https://trade.amx.com/assets/manuals/NetLinxStudio.StyleGuide.pdf
  • Thanks Roger
  • Here is a simple array, get last example to make a button event more portable, scalable, and readable. The workflow on the UI side is to select a source and then destination(s).
    DEFINE_DEVICE //Touch Panels
    dvTP_Theater            =10001:1:0;    // CV7
    dvTP_Kitchen            =10002:1:0;    // CV10 w/video
    dvTP_MBR                 =10003:1:0;    // CV7 w/video
    
    DEFINE_CONSTANT //Device Arrays
    DEV dvGlobalTP [] =
    {
        dvTP_Theater,
        dvTP_Kitchen,
        dvTP_MBR
    };
    
    DEFINE_CONSTANT //Touch Panel Buttons
    INTEGER nTPBtn_DASourceSelect [] = //Source Select Buttons
    {
        11,//Source 1
        12,//Source 2
        13,//Source 3
        14,//Source 4
        15 //OFF
    };
    
    INTEGER nTPBtn_DAZoneSelect [] =  //Zone Selection
    {
        101, //Zone 1
        102, //Zone 2
        103, //Zone 3
        104, //Zone 4
        105, //Zone 5
        106, //Zone 6
        107, //Zone 7
        108, //Zone 8
        109, //Zone 9
        110, //Zone 10
        111, //Zone 11
        112, //Zone 12
        113, //Zone 13
        114, //Zone 14
        115, //Zone 15
        116, //Zone 16
        117  //17 All Zones
    };
    
    DEFINE_FUNCTION fnChangeDistributedZoneSource (INTEGER nOutput, INTEGER nInput)
    {
        SEND_STRING 0, "'Change Distributed Zone ', ITOA(nOutput), ' to Input ', ITOA(nInput)"
    
        SWITCH (nOutput)
        {
             CASE nDAZoneAll: //ALL ZONES
             {
                 IF (nInput <> LENGTH_ARRAY(nTPBtn_DASourceSelect)) //Isn't Source OFF
                 {
                      SEND_COMMAND vdvMatrixAudio, "'INPUTSELECT-',ITOA(nInput)"
                 }
                 ELSE //OFF
                 {
                      SEND_COMMAND vdvMatrixAudio, "'INPUT-OTHER,0'"
                 }
             }
             DEFAULT:
             {
                 IF (nInput <> LENGTH_ARRAY(nDASourceBtns)) //Isnt Source OFF
                 {
                      SEND_COMMAND vdvMatrixAudio[nOutput], "'INPUTSELECT-',ITOA(nInput)"  //New Requested Source
                 }
                 ELSE //OFF
                 {
                      SEND_COMMAND vdvMatrixAudio[nOutput], "'INPUT-OTHER,0'"
                 }
             }
        }
    }
    
    DEFINE_EVENT //Touch Panel Events
    BUTTON_EVENT[dvGlobalTP, nTPBtn_DASourceSelect]
    {
        PUSH:
        {
             nTempSource= GET_LAST(nTPBtn_DASourceSelect);
        }
    }
    BUTTON_EVENT[dvGlobalTP, nTPBtn_DAZoneSelect]
    {
        PUSH:
        {
             fnChangeDistributedZoneSource(GET_LAST(nTPBtn_DAZoneSelect), nTempSource);
        }
    }
    
Sign In or Register to comment.