Home AMX User Forum NetLinx Studio

More stupid questions (I'm learning!)

Hey guys,

I've made some progress with learning my AMX system and NetLinx. I've successfully created a web panel and am able to turn on and off my projector through serial. I know, real impressive, right? Anyway, still a lot left to do. I would like to hook up some IR devices, as well as figure out netlinx modules. Some concerns:
  • Code Methods - Right now I have just one main source file. I've defined my projector on the serial port on the NXI. Then, under button events, I have something like the following:

    BUTTON_EVENT[TP1,1]
    {
         PUSH:
         {
              TO[TP1,1]
              SEND_STRING PROJ, "'C00',$0D,$0A"
    
         }
         RELEASE:
         {
         }
         HOLD[5,REPEAT]:
         {
         }
    }
    

    This is being triggered by button "1" on my web panel. I have one of these blocks of code for each button on my only touch panel. This doesn't seem like the right way to do it though - I feel like I should be defining the buttons for various devices, then referring to them in a more user friendly way (like SEND_STRING PROJ,"poweron") or something - but I don't know how to do this. It just doesn't seem like I should be writing code for each button, especially when a few buttons are likely to do the same things. What is the correct way?
  • IRL Files - How do I use them? I've found quite a few for my devices, but I'm not exactly sure what to do with them, nor how to use the commands from my program.
  • NetLinx Modules - Again, found one for a one of my devices. How do I implement these?

Sorry to be so long-winded. I'm sure these are some stupid questions to some of you long-time programmers, but I'm just learning as I go - so any help is much appreciated.

Thanks in advance!

Dan

Comments

  • adysadys Posts: 395
    your code looks ok, you can declare device command like this:

    char powerCommand[] = "'C00',$0D,$0A" in the variable section.


    you don't need the "to" command, from what I undestand its good only when you are listen to mulitple devices and want to pass it to a specific one.




    About IRL, its very simple.

    Add it to your project to IR (note that if its read only you will get error while uploading)

    Then map it (right click) to the device that you have declared in the source ( same as you did for the pojector)

    upload it and thats all from the project side.


    to use it, open the irl file with IREdit and look on the command numbers.

    if power on is command 1, all you need to do is to send a pulse command to the device like this:

    pulse[yourDevice, 1]




    Modules - http://www.amxforums.com/showthread.php?t=2752

    Quting from the second response "Check out tech notes 271 (Module Example) and 375 (How to Write Your Own Netlinx Modules)"
  • matt95gsrmatt95gsr Posts: 165
    adys wrote:
    you don't need the "to" command, from what I undestand its good only when you are listen to mulitple devices and want to pass it to a specific one.

    Actually, the TO[TP1,1] statement will turn on channel 1 of TP1 while the PUSH event is active, in other words providing feedback to the panel that the button is active or being pushed. There are other ways to do that, but it's generally an easy and effective method of handling momentary type feedback from the code. In this way, it will act pretty much the same as if you had set the Feedback Type to Momentary in TPDesign.
  • adysadys Posts: 395
    matt95gsr wrote:
    Actually, the TO[TP1,1] statement will turn on channel 1 of TP1 while the PUSH event is active, in other words providing feedback to the panel that the button is active or being pushed. There are other ways to do that, but it's generally an easy and effective method of handling momentary type feedback from the code. In this way, it will act pretty much the same as if you had set the Feedback Type to Momentary in TPDesign.

    thanks, I didn't know that...

    I ususaly work with Momentary or channel, and turn it on like this if needed

    [tp, channel] = 1

    Good to know
  • viningvining Posts: 4,368
    Using a "TO [Button.Input.Device, Button.Input.Channel]" or something similar instead of setting the button as momemtary in TP4 is a little nicer because w/ the "TO" you know the button_event is triggering and communications between the TP and Master are OK. That said, I still use both "TOs and Momemtary" on buttons. (one or the other not both)
  • dmurray14dmurray14 Posts: 80
    Thanks guys, much appreciated! Still not completely clear on declaring commands though:

    adys wrote:
    your code looks ok, you can declare device command like this:

    char powerCommand[] = "'C00',$0D,$0A" in the variable section.


    you don't need the "to" command, from what I undestand its good only when you are listen to mulitple devices and want to pass it to a specific one.

    What section do I declare this under? How do I then use that command? And how do I seperate them for the different devices? For instance, powerCommand for my projector won't be the same for powerCommand for my tuner.

    Thanks!

    Dan
  • adysadys Posts: 395
    under DEFINE_VARIABLE

    put your strings like this

    CHAR DEVICE_COMMAND[] = {$FE,$03,$A1,$10,$00,$B4}

    in your code -

    SEND_STRING PROJ, DEVICE_COMMAND
  • ericmedleyericmedley Posts: 4,177
    adys wrote:
    under DEFINE_VARIABLE

    put your strings like this

    CHAR DEVICE_COMMAND[] = {$FE,$03,$A1,$10,$00,$B4}

    in your code -

    SEND_STRING PROJ, DEVICE_COMMAND

    I have to admit that I don't use the variable declaration method if I'm only going to be doing the projector commnad once or twice. I don't like having to run up the scroll bar to see what the heck the command is. I only will do this if I find myself putting in a hex string command more than 3 or so times.

    I usually just comment at the end that it's a projector on command.

    It helps avoids the spagetti code syndrome.
  • adysadys Posts: 395
    ericmedley wrote:
    I have to admit that I don't use the variable declaration method if I'm only going to be doing the projector commnad once or twice. I don't like having to run up the scroll bar to see what the heck the command is. I only will do this if I find myself putting in a hex string command more than 3 or so times.

    I usually just comment at the end that it's a projector on command.

    It helps avoids the spagetti code syndrome.

    I my opinion there is not such thing too much consts and defines in a program, even for one time use.
  • viningvining Posts: 4,368
    ericmedley wrote:
    It helps avoids the spagetti code syndrome.

    First, I would probably create a constant not a variable to hold this value.

    DEFINE_CONSTANT

    CRLF[2] = {$0D,$0A} ;
    CHAR PROJ_PWR_OFF = 'C00' ;
    CHAR PROJ_PWR_ON = 'C01' ; //just a guess!

    and in the button_event:

    SEND_STRING PROJ, "PROJ_PWR_OFF,CRLF" ;

    I just find it easier to look at and know exactly what the command is. This is also likely one of only two places you'll use this. Here and a shut down routine. If I'm in a hurry then I probably wouldn't create any constants.

    As far as spagetti goes, there was a thread a while back about creating multiple DEFINE_CONSTSANTs and DEFINE_VARIABLEs which I find very usefull to categorize constants or variables so that I don't have to scroll down endless lists. Long button arrays are the worst so I now create a seperate DEFINE_VARIABLE for each button_array or category and a seperate DEFINE_CONSTANT list for the various categories I need.


    Here's an example of multiple DEFINE_CONSTANTs for a TV module. When the code is folded I can basically just have the section of constants I'm working with open for reference and the code I'm writing. I can't stand long scrolling lists and I prefer to have everything viewable at the same time although seldom can I view everything at the same time especially w/ my over bracing habits.
    DEFINE_CONSTANT // general constants
    
    RCV_STR_TIME_OUT = 80 ;
    FPWR_OFF 	 = 0 ;
    FPWR_ON          = 1 ;
    FRnM_LOCK        = 0 ;
    FR_LOCK          = 1 ;
    FM_LOCK          = 2 ;
    FRnM_UNLOCK      = 3 ;
    FOSD_OFF         = 0 ;
    FOSD_ON          = 1 ;
    FOSD_OND         = 2 ;
    FPICMODE_NAT     = 0 ;
    FPICMODE_FINE    = 1 ;
    FPICMODE_EFF     = 2 ;
    FPICMODE_CONV    = 3 ;
    FPICMODE_STILL   = 4 ;
    FVID_RGB_DSUB    = 0 ;
    FVID_RGB_BNC     = 1 ;
    FVID_DVI         = 2 ;
    FVID_C_RCABNC    = 3 ;
    FVID_C_RCAD      = 4 ;
    FVID_VIDEO       = 5 ;
    FVID_SVID        = 6 ;
    FASPECT_NORM     = 0 ;
    FASPECT_WIDE1    = 1 ;
    FASPECT_WIDE2    = 2 ;
    FASPECT_ZOOM1    = 3 ;
    FASPECT_ZOOM2    = 4 ;
    FASPECT_AUTO1    = 8 ;
    FNOISE_OFF       = 0 ;
    FNOISE_MIN       = 1 ;
    FNOISE_STD       = 2 ;
    FNOISE_MAX       = 3 ;
    FCTEMP_NEG3500   = 0 ;
    FCTEMP_STANDARD  = 1 ;
    FCTEMP_POS3500   = 2 ;
    FCTEMP_USER      = 3 ;
    
    F_VT_ERROR_TXT   = 2 ;
    
    DEFINE_CONSTANT//Send strings/commands
    
    ////////////////// STRING PARTS /////
    CRLF[2]                   = {$0D,$0A} ;
    CR[1]   		  = {$0D} ;
    FUJ_QUEUE_DELIM[1]        = {$0D} ;
    CHAR FSEND_START[]	  = '@G' ;
    CHAR FSEND_TERMINATE[]    = '@Q' ;
    CHAR FSEND_PRE_STR[]      = '%A' ;
    /////////////////// POWER  //////////
    CHAR FSEND_POFF[] 	  = '0000' ;
    CHAR FSEND_PON[]          = '0001' ;	
    /////////////////// INPUTS  /////////
    CHAR FSEND_RGB1[] 	  = '1000' ;
    CHAR FSEND_RGB2[]         = '1001' ;
    CHAR FSEND_DVI[]          = '1002' ;
    CHAR FSEND_CVID1[]        = '1010' ;
    CHAR FSEND_CVID2[]        = '1011' ;
    CHAR FSEND_VIDEO[]        = '1012' ;
    CHAR FSEND_SVID[]         = '1014' ;
    CHAR FSEND_TV[]           = '1030' ;
    ///////////////// ASPECT  ///////////	
    CHAR FSEND_NORM[]         = '1100' ;
    CHAR FSEND_WIDE1[]        = '1101' ;
    CHAR FSEND_WIDE2[]        = '1102' ;
    CHAR FSEND_ZOOM1[]        = '1103' ;
    CHAR FSEND_ZOOM2[]        = '1104' ;
    CHAR FSEND_AUTO[]         = '1108' ;
    //////// REM0TE & MAIN UNIT L0CK ////
    CHAR FSEND_LOCKALL[]      = '0400' ;
    CHAR FSEND_LOCKREMOTE[]   = '0401' ;
    CHAR FSEND_LOCKMAIN[]     = '0402' ;
    CHAR FSEND_UNLOCKALL[]    = '0403' ;
    ////////////////  0SD ///////////////
    CHAR FSEND_OSD_AUTO_OFF[] = '0100' ;
    CHAR FSEND_OSD_AUTO_ON[]  = '0101' ;
    CHAR FSEND_OSD_AUTO_OND[] = '0102' ;// on dark
    /////////// VIDEO ADJUSMENTS ////////
    CHAR FSEND_CNTRST_VALUE[] = '1300' ;
    CHAR FSEND_BRIGHT_VALUE[] = '1301' ;
    CHAR FSEND_COLOR_VALUE[]  = '1302' ;
    CHAR FSEND_TINT_VALUE[]   = '1303' ;
    CHAR FSEND_SHARP_VALUE[]  = '1304' ;
    CHAR FSEND_NOISE_VALUE[]  = '1305' ;
    CHAR FSEND_C_TEMP_VALUE[] = '1306' ;
    ////////////// PICTURE MODES  ///////
    CHAR FSEND_PIC_MODE[]     = '130F' ;
    CHAR FSEND_PICM_NAT[]     = '00' ;
    CHAR FSEND_PICM_FINE[]    = '01' ;
    CHAR FSEND_PICM_EFF[]     = '02' ;
    CHAR FSEND_PICM_CONV[]    = '03' ;
    CHAR FSEND_PICM_STILL[]   = '04' ;
    
    DEFINE_CONSTANT//GET STATUS SEND CMDs
    
    CHAR FSEND_GET_PWR[]      = '0080' ;
    CHAR FSEND_GET_OSD[]      = '0180' ;
    CHAR FSEND_GET_LOCKS[]    = '0480' ;
    CHAR FSEND_GET_VID_IN[]   = '1080' ;
    CHAR FSEND_GET_ASPECT[]   = '1180' ;
    CHAR FSEND_GET_CNTRST[]   = '1380' ;
    CHAR FSEND_GET_BRIGHT[]   = '1381' ;
    CHAR FSEND_GET_COLOR[]    = '1382' ;
    CHAR FSEND_GET_TINT[]     = '1383' ;
    CHAR FSEND_GET_SHARP[]    = '1384' ;
    CHAR FSEND_GET_NOISE[]    = '1385' ;
    CHAR FSEND_GET_CTEMP[]    = '1386' ;
    CHAR FSEND_GET_PICMODE[]  = '138F' ;
    
    DEFINE_CONSTANT//Receive commands
    
    CHAR FRCV_PREFIX_OK[]     = '@S'  ; 
    CHAR FRCV_PREFIX_ERR[]    = '@E'  ;
    CHAR FRCV_REPLY_0[]       = 'S00' ;
    CHAR FRCV_REPLY_1[]       = 'S01' ;
    CHAR FRCV_REPLY_2[]       = 'S02' ;
    CHAR FRCV_REPLY_3[]       = 'S03' ;
    CHAR FRCV_REPLY_4[]       = 'S04' ;
    CHAR FRCV_REPLY_5[]       = 'S05' ;
    CHAR FRCV_REPLY_6[]       = 'S06' ;
    CHAR FRCV_REPLY_7[]       = 'S07' ;
    CHAR FRCV_REPLY_8[]       = 'S08' ;
    CHAR FRCV_REPLY_9[]       = 'S09' ;
    CHAR FRCV_REPLY_10[]      = 'S10';
    CHAR FRCV_REPLY_11[]      = 'S11';
    CHAR FRCV_REPLY_12[]      = 'S12';
    CHAR FRCV_REPLY_13[]      = 'S13';
    CHAR FRCV_REPLY_14[]      = 'S14';
    CHAR FRCV_REPLY_0E[]      = 'S0E' ;
    CHAR FRCV_REPLY_80[]      = 'S80' ;
    CHAR FRCV_ERR_REPLY_0[]   = 'E00' ;
    CHAR FRCV_ERR_REPLY_1[]   = 'E01' ;
    CHAR FRCV_ERR_REPLY_2[]   = 'E02' ;
    CHAR FRCV_ERR_REPLY_3[]   = 'E03' ;
    
    DEFINE_CONSTANT//BUTTONS INDEXES
    
    FBTN_PWR_OFF              = 1 ;
    FBTN_PWR_ON               = 2 ;
    FBTN_TGL_PU               = 47 ;
    
    BUTTON_EVENT[dvTP,nCH_BtnArry]
         
         {
         PUSH:
    	  {
    	  STACK_VAR INTEGER nBTN
    	  nBTN = GET_LAST(nCH_BtnArry)
    	  
    	  If (nFUJ_DeBug)
    	       {
    	       SEND_STRING 0,"'Fujitsu ',fnDEV_TO_STRING(BUTTON.INPUT.DEVICE),
    					     '-CHANNEL ',itoa(nCH_BtnArry[nBTN]),
    						  ' Line-<',ITOA(__LINE__),'>',CRLF" ;
    	       }
    	  if(sFUJ_Stat.PWR || nBTN == nCH_BtnArry[FBTN_PWR_ON ] || nBTN == nCH_BtnArry[FBTN_TGL_PU])
    	       {
    	       SWITCH(nBTN)
    		    {
    		    CASE 1: 	//POWER OFF
    			 {
    			 cFUJ_CMDQueue = "cFUJ_CMDQueue,FSEND_POFF,FUJ_QUEUE_DELIM" ;
    			 cFUJ_QueryQueue = "cFUJ_QueryQueue,FSEND_GET_PWR,FUJ_QUEUE_DELIM" ;
    			 }
    		    CASE 2:	//POWER ON
    			 {
    			 cFUJ_CMDQueue = "cFUJ_CMDQueue,FSEND_PON,FUJ_QUEUE_DELIM" ;
    			 cFUJ_QueryQueue = "cFUJ_QueryQueue,FSEND_GET_PWR,FUJ_QUEUE_DELIM" ;
    			 }
    
  • adysadys Posts: 395
    vining wrote:
    ericmedley wrote:


    First, I would probably create a constant not a variable to hold this value.

    My mistake, you are right. should be in consts and not variable.
  • dmurray14dmurray14 Posts: 80
    Thanks for all the help guys!

    I'm stumped right now. Can any of you figure out why this code turns on the receiver:
    BUTTON_EVENT[WP1,30] //test tools onk on
    {
         PUSH:
         {
              TO[WP1,30]
    	  PULSE[onkyo,27]
         }
         RELEASE:
         {
         }
         HOLD[5,REPEAT]:
         {
         }
    }
    


    yet this one does not?
    BUTTON_EVENT[WP1,1] //watch satellite
    {
         PUSH:
         {
              TO[WP1,1]
              SEND_STRING PROJ, "'C00',$0D,$0A" //proj on
    	  PULSE[onkyo,27]//onkyo on
    	  SEND_STRING PROJ, "'C26',$0D,$0A" //proj to input 3
    	  PULSE[onkyo,84]//onkyo input 3
         }
         RELEASE:
         {
         }
         HOLD[5,REPEAT]:
         {
         }
    }
    

    Thanks in advance...

    Dan
  • adysadys Posts: 395
    I had once a problem like this, I add wait 1 and that solve it:

    WAIT 1 PULSE[onkyo,27]

    Try to add wait before the diffrent device command to eliminate the problem


    I don't know the reason, I will happy to hear from someone that knows..
  • dchristodchristo Posts: 177
    dmurray14 wrote:
    Thanks for all the help guys!

    I'm stumped right now. Can any of you figure out why this code turns on the receiver:
    BUTTON_EVENT[WP1,30] //test tools onk on
    {
         PUSH:
         {
              TO[WP1,30]
    	  PULSE[onkyo,27]
         }
         RELEASE:
         {
         }
         HOLD[5,REPEAT]:
         {
         }
    }
    


    yet this one does not?
    BUTTON_EVENT[WP1,1] //watch satellite
    {
         PUSH:
         {
              TO[WP1,1]
              SEND_STRING PROJ, "'C00',$0D,$0A" //proj on
    	  PULSE[onkyo,27]//onkyo on
    	  SEND_STRING PROJ, "'C26',$0D,$0A" //proj to input 3
    	  PULSE[onkyo,84]//onkyo input 3
         }
         RELEASE:
         {
         }
         HOLD[5,REPEAT]:
         {
         }
    }
    

    Thanks in advance...

    Dan

    Only one channel of an IR port can be transmitting at any one time. Try this:
    PUSH:
         {
              TO[WP1,1]
              SEND_STRING PROJ, "'C00',$0D,$0A" //proj on
    	  PULSE[onkyo,27]//onkyo on
    	  SEND_STRING PROJ, "'C26',$0D,$0A" //proj to input 3
    	  Wait 10 {PULSE[onkyo,84]}  //onkyo input 3
         }
    
  • NMarkRobertsNMarkRoberts Posts: 455
    Quite apart from the failure to power up if you immediately pulse the channel select, if the Onkyo is like many other receivers, you have to delay the channel select by as much as 5 or 10 seconds after the power on as it will ignore the command during its warmup / bootup.

    Accepting that this is your first attempt and that what you have coded will generally work, the "industrial strength" way to handle the receiver is to write a module which:

    (a) tracks its (presumed) state - note that this can only be guesswork; the unit might not even be plugged in

    (b) does not attempt to do things that it cannot do in a given state

    (c) queues commands with appropriate pauses between

    Why bother? If you code it and you use it then you will know its limitations. But for instance, if there is a switchon delay as I surmised, then if you switch it on and immediately switch it off, the switch off will be ignored.

    The same goes for the projector, but more so!

    NB don't assume that AMX modules do all of (a), (b) and (c). The Denon receiver serial module that I worked with recently certainly doesn't.
  • dmurray14dmurray14 Posts: 80
    Thanks for all the great help everyone - I really appreciate it. I'm about halfway done the system, and it's working perfectly, every time. Really pumped to get the touchscreens in the system.

    Again, much appreciated!

    Dan
  • ericmedleyericmedley Posts: 4,177
    adys wrote:
    I my opinion there is not such thing too much consts and defines in a program, even for one time use.

    I guess I'd say that declaring a variable/constant to reference a single command is needless use of RAM. Granted that the bad old days of limited RAM are pretty much gone. But I think it's still a good code practice. All those little uses of RAM add up over the long haul.
    DEFINE_CONSTANT
    
    cProjector_On_Command={$FE,$03,$A1,$10,$4B,$FF}
    
    DEFINE_EVENT
    
    BUTTON_EVENT[dvTP_1,1]
    {
    push:
      {
      send_string dvProjector, cProjector_On_Command
      }
    }
    
    

    uses more lines of code and more RAM than...
    BUTTON_EVENT[dvTP_1,1]
    {
    PUSH:
      {
      send_string dvProjector, "$FE,$03,$A1,$10,$4B,$FF" // PROJECTOR ON COMMAND
      }
    }
    


    A good example of when I like to create a token for the command is for Rotel Processors. They have a myriad of commands that must be used over and over again. The hex strings are a nuisance. I then will declare a constant and/or variable to store the commands.

    There's nothing really wrong with either method. They both have their advantages and disadvantages. As long as the code is well documented it doesn't really matter much.
  • jjamesjjames Posts: 2,908
    My 2 cents...

    As far as sending serial commands out to devices, and not really having to rely on remembering what the protocol is, or scrolling up to try and remember what exactly you named your CONSTANT, I make an array of the commands and then put them in standard IR order. That way, when I'm doing my touch panel, 1 = play, 2 = stop, 3 pause, 27 = power on, and so forth. Since we work with certain equipment on a regulalr basis (the Integra recievers, DVD and CD players / changers) I've made the list for all of them. Here's a bit of sample code:
    DEFINE_CONSTANT
    CHAR CD_COMMANDS[][13] =
    {        
    	 '!4PLY'		//  1	- PLAY
    	,'!4STP'		//  2	- STOP
    	,'!4PAS'		//  3	- PAUSE
    	,'!4SCNFF'		//  4	- FAST FORWARD
    	,'!4SCNFR'		//  5	- REWIND
    	,'!4SKPUP'		//  6	- SKIP UP
    	,'!4SKPDN'		//  7	- SKIP DOWN
    	,''		//  8
    	,''		//  9
    	,'!4NUM00'		// 10	- DIGIT  0
    	,'!4NUM01'		// 11	- DIGIT  1 
    	,'!4NUM02'		// 12	- DIGIT  2
    	,'!4NUM03'		// 13	- DIGIT  3
    	,'!4NUM04'		// 14	- DIGIT  4
    	,'!4NUM05'		// 15	- DIGIT  5
    	,'!4NUM06'		// 16	- DIGIT  6
    	,'!4NUM07'		// 17	- DIGIT  7
    	,'!4NUM08'		// 18	- DIGIT  8
    	,'!4NUM09'		// 19	- DIGIT  9
    	,'!4NUM10'		// 20	- DIGIT 10+
    // etc.
    }
    
    DEFINE_EVENT
    BUTTON_EVENT[dv_TP,nALL_CMDS]
    {
    PUSH:
    	{
    		
    		LOCAL_VAR INTEGER nPANEL
    		LOCAL_VAR INTEGER nBTN
    		LOCAL_VAR CHAR cTEXT[4][12]
    		STACK_VAR INTEGER iSRC;
    		nPANEL = GET_LAST(dv_TP)
    		nBTN = BUTTON.INPUT.CHANNEL
    		
    		IF(nSOURCE_CTRL[nPANEL])
    			iSRC = nHOUSE_MUSIC
    		
    		ELSE
    			iSRC = nAV_ZONE_SOURCE[nPNL_AV[nPANEL]];
    		
    				// MANAGE DEVICE CONTROL
    		SWITCH(iSRC)
    		{
    			// MANAGE IR DEVICES
    			CASE nSRC_DVD:
    			CASE nSRC_VCR:
    			CASE nSRC_CABLE:		// CABLE MUSIC COMMANDS
    			CASE nSRC_MUSIC:
    			CASE nSRC_COMBO:
    			{
    				SELECT
    				{
    					// Up, down, left right buttons - continuous scrolling
    					ACTIVE((nBTN>=45 && nBTN<=48) &&
    							 iSRC==nSRC_CABLE):	// CONTINUOUS IR OUTPUT
    						MIN_TO[IR_DEVICE[nPANEL],nBTN]
    					
    					// All other buttons
    					ACTIVE(1):
    					{
    						// Current source is not the cable box, so control the current IR device
    						SEND_COMMAND IR_DEVICE[nPANEL],"'SP',nBTN"
    					}
    				}
    			}
    			
    						
    			CASE nSRC_DTR_RADIO:	// Radio from DTR Reciever
    			{
    				SEND_STRING dv_RCVR[nRCVR_MAP[nPNL_AV[nPANEL]]],"DTR_TUNER[nBTN],CR"
    			}
    			
    			CASE nSRC_CD:
    			{
    				SEND_STRING dvCDC,"CD_COMMANDS[nBTN],CR"
    				
    			}
    		}
    	}
    }
    

    For some reason the formatting looks really funky, sorry about that but hopefully this helps someone. nALL_CMDS would go from 1 to 99. I figure 99 is a good number for maximum control commands for a device. I rarely see a device that can use most of that.

    Anyway, this is just my 2 cents on controlling serial devices and not really having to worry about the protocol too much. I know this works great devices that don't use a checksum, and I know it's not an end-all solution, but it has turned out to be very usefull with my code.
  • jweatherjweather Posts: 320
    ericmedley wrote:
    I guess I'd say that declaring a variable/constant to reference a single command is needless use of RAM. Granted that the bad old days of limited RAM are pretty much gone. But I think it's still a good code practice. All those little uses of RAM add up over the long haul.

    Variables do use up RAM (slowly), but constants do not. Constants are processed and substituted by the compiler at compile-time. The two examples you gave, one with a constant and one without, will use an identical amount of storage space in RAM and binary code. Only the source code will be different.

    With that said, I don't see much point in using a constant for a one-time-use string. The nice thing about them is having a centralized place to change values globally for your program, as well as being able to give them "self-documenting" names, so you can say:

    state = STATE_SEND_PASS

    rather than

    state = 5 // send the password

    Auto-completion makes them even more useful.

    Jeremy
  • alexanboalexanbo Posts: 282
    You may want to use the SP command here to stack the pulses, otherwise as was pointed out the IR can only do one thing.

    So you'd do something like Send_Command onkyo,"'SP",27" and then 84 and the pulses would get stacked and fired as per the parameters setup by cton and ctof
    BUTTON_EVENT[WP1,1] //watch satellite
    {
         PUSH:
         {
              TO[WP1,1]
              SEND_STRING PROJ, "'C00',$0D,$0A" //proj on
    	  PULSE[onkyo,27]//onkyo on
    	  SEND_STRING PROJ, "'C26',$0D,$0A" //proj to input 3
    	  PULSE[onkyo,84]//onkyo input 3
         }
         RELEASE:
         {
         }
         HOLD[5,REPEAT]:
         {
         }
    }
    

    Thanks in advance...

    Dan[/QUOTE]
  • NMarkRobertsNMarkRoberts Posts: 455
    Literals bad constants good

    Naturally priority 1 is to write code that works.

    Somewhere further down the list is "write code that can be understood" and when you get into practice this doesn't conflict with "write code quickly". Using a constant instead of a literal almost always enhances readability.

    Also on the list is "write code that can be extended / modified easily". If you start by entombing absolutely every literal value into a constant, then you never need to worry about getting it wrong later when you re-use the value.

    "Write code that's small or fast" isn't on the list at all, until you run out of space or time, which is improbable with NetLinx and you can fix it easily when it arises.
  • jjamesjjames Posts: 2,908
    Naturally priority 1 is to write code that works.
    Well said! I couldn't agree more.
  • ericmedleyericmedley Posts: 4,177
    Naturally priority 1 is to write code that works.

    Somewhere further down the list is "write code that can be understood" and when you get into practice this doesn't conflict with "write code quickly". Using a constant instead of a literal almost always enhances readability.

    Also on the list is "write code that can be extended / modified easily". If you start by entombing absolutely every literal value into a constant, then you never need to worry about getting it wrong later when you re-use the value.

    "Write code that's small or fast" isn't on the list at all, until you run out of space or time, which is improbable with NetLinx and you can fix it easily when it arises.

    Some of the larger system programs I've done do get quite memory-hungry and require a lot of RAM.

    I think I may have started a fire storm by what was meant as a simple comment. I originally said that there were times that I didn't create a token for a one-time-only serial string. I wasn't necessarily condoning the act, just an admission.

    What I've learned over the many years of doing this is that programmers bristle when you start to discuss ways of going about doing something. I personally don't enjoy these disucssion because they seem to disolve into an argument over something that is strictly an opinion. We do have guidelines that are helpful to follow. But, for the most part, programming is still the 'Wild West.'

    A big 'here-here' to Marks comment that first and foremost, get it working. All the pretty code is useless if it doesn't work. I've suffered through that here for about a year and a half.
  • dmurray14dmurray14 Posts: 80
    Guys, I agree whole-heartedly. By day I do a lot of web application design, and I'd be happy to talk about the importance of readable code. However I also understand the time and the place for a "quick fix".

    The NetLinx language is clearly very new to me - but I appreciate all the help you guys have given. This forum has proven to be a great resource with very helpful individuals - while this started as me just messing around with some hand-me-down equipment, I've since bought 3 touchscreens and an audio switcher, I'm sure more to come. Which actually brings me to my next question (they keep coming!) - Whats the best way to reuse pieces of code for another panel? Just copy-paste and maybe do a find-replace on the touchpanel device? And one other question - I somehow ended up with two 315mhz panels - are they going to play nice?

    Again all the help is much appreciated. You've all made me into an AMX freak - I want to do this more often now!

    Thanks,
    Dan
  • jjamesjjames Posts: 2,908
    Glad you're loving it! The forums are an amazing resource.
  • NMarkRobertsNMarkRoberts Posts: 455
    ericmedley wrote:
    Some of the larger system programs I've done do get quite memory-hungry and require a lot of RAM.

    I'd like to learn what makes that happen. Are you doing something interesting with it?
  • How to pass this through modules
    vining wrote: »
    ericmedley wrote:


    First, I would probably create a constant not a variable to hold this value.

    DEFINE_CONSTANT

    CRLF[2] = {$0D,$0A} ;
    CHAR PROJ_PWR_OFF = 'C00' ;
    CHAR PROJ_PWR_ON = 'C01' ; //just a guess!

    and in the button_event:

    SEND_STRING PROJ, "PROJ_PWR_OFF,CRLF" ;

    I just find it easier to look at and know exactly what the command is. This is also likely one of only two places you'll use this. Here and a shut down routine. If I'm in a hurry then I probably wouldn't create any constants.

    As far as spagetti goes, there was a thread a while back about creating multiple DEFINE_CONSTSANTs and DEFINE_VARIABLEs which I find very usefull to categorize constants or variables so that I don't have to scroll down endless lists. Long button arrays are the worst so I now create a seperate DEFINE_VARIABLE for each button_array or category and a seperate DEFINE_CONSTANT list for the various categories I need.


    Here's an example of multiple DEFINE_CONSTANTs for a TV module. When the code is folded I can basically just have the section of constants I'm working with open for reference and the code I'm writing. I can't stand long scrolling lists and I prefer to have everything viewable at the same time although seldom can I view everything at the same time especially w/ my over bracing habits.
    DEFINE_CONSTANT // general constants
    
    RCV_STR_TIME_OUT = 80 ;
    FPWR_OFF 	 = 0 ;
    FPWR_ON          = 1 ;
    FRnM_LOCK        = 0 ;
    FR_LOCK          = 1 ;
    FM_LOCK          = 2 ;
    FRnM_UNLOCK      = 3 ;
    FOSD_OFF         = 0 ;
    FOSD_ON          = 1 ;
    FOSD_OND         = 2 ;
    FPICMODE_NAT     = 0 ;
    FPICMODE_FINE    = 1 ;
    FPICMODE_EFF     = 2 ;
    FPICMODE_CONV    = 3 ;
    FPICMODE_STILL   = 4 ;
    FVID_RGB_DSUB    = 0 ;
    FVID_RGB_BNC     = 1 ;
    FVID_DVI         = 2 ;
    FVID_C_RCABNC    = 3 ;
    FVID_C_RCAD      = 4 ;
    FVID_VIDEO       = 5 ;
    FVID_SVID        = 6 ;
    FASPECT_NORM     = 0 ;
    FASPECT_WIDE1    = 1 ;
    FASPECT_WIDE2    = 2 ;
    FASPECT_ZOOM1    = 3 ;
    FASPECT_ZOOM2    = 4 ;
    FASPECT_AUTO1    = 8 ;
    FNOISE_OFF       = 0 ;
    FNOISE_MIN       = 1 ;
    FNOISE_STD       = 2 ;
    FNOISE_MAX       = 3 ;
    FCTEMP_NEG3500   = 0 ;
    FCTEMP_STANDARD  = 1 ;
    FCTEMP_POS3500   = 2 ;
    FCTEMP_USER      = 3 ;
    
    F_VT_ERROR_TXT   = 2 ;
    
    DEFINE_CONSTANT//Send strings/commands
    
    ////////////////// STRING PARTS /////
    CRLF[2]                   = {$0D,$0A} ;
    CR[1]   		  = {$0D} ;
    FUJ_QUEUE_DELIM[1]        = {$0D} ;
    CHAR FSEND_START[]	  = '@G' ;
    CHAR FSEND_TERMINATE[]    = '@Q' ;
    CHAR FSEND_PRE_STR[]      = '%A' ;
    /////////////////// POWER  //////////
    CHAR FSEND_POFF[] 	  = '0000' ;
    CHAR FSEND_PON[]          = '0001' ;	
    /////////////////// INPUTS  /////////
    CHAR FSEND_RGB1[] 	  = '1000' ;
    CHAR FSEND_RGB2[]         = '1001' ;
    CHAR FSEND_DVI[]          = '1002' ;
    CHAR FSEND_CVID1[]        = '1010' ;
    CHAR FSEND_CVID2[]        = '1011' ;
    CHAR FSEND_VIDEO[]        = '1012' ;
    CHAR FSEND_SVID[]         = '1014' ;
    CHAR FSEND_TV[]           = '1030' ;
    ///////////////// ASPECT  ///////////	
    CHAR FSEND_NORM[]         = '1100' ;
    CHAR FSEND_WIDE1[]        = '1101' ;
    CHAR FSEND_WIDE2[]        = '1102' ;
    CHAR FSEND_ZOOM1[]        = '1103' ;
    CHAR FSEND_ZOOM2[]        = '1104' ;
    CHAR FSEND_AUTO[]         = '1108' ;
    //////// REM0TE & MAIN UNIT L0CK ////
    CHAR FSEND_LOCKALL[]      = '0400' ;
    CHAR FSEND_LOCKREMOTE[]   = '0401' ;
    CHAR FSEND_LOCKMAIN[]     = '0402' ;
    CHAR FSEND_UNLOCKALL[]    = '0403' ;
    ////////////////  0SD ///////////////
    CHAR FSEND_OSD_AUTO_OFF[] = '0100' ;
    CHAR FSEND_OSD_AUTO_ON[]  = '0101' ;
    CHAR FSEND_OSD_AUTO_OND[] = '0102' ;// on dark
    /////////// VIDEO ADJUSMENTS ////////
    CHAR FSEND_CNTRST_VALUE[] = '1300' ;
    CHAR FSEND_BRIGHT_VALUE[] = '1301' ;
    CHAR FSEND_COLOR_VALUE[]  = '1302' ;
    CHAR FSEND_TINT_VALUE[]   = '1303' ;
    CHAR FSEND_SHARP_VALUE[]  = '1304' ;
    CHAR FSEND_NOISE_VALUE[]  = '1305' ;
    CHAR FSEND_C_TEMP_VALUE[] = '1306' ;
    ////////////// PICTURE MODES  ///////
    CHAR FSEND_PIC_MODE[]     = '130F' ;
    CHAR FSEND_PICM_NAT[]     = '00' ;
    CHAR FSEND_PICM_FINE[]    = '01' ;
    CHAR FSEND_PICM_EFF[]     = '02' ;
    CHAR FSEND_PICM_CONV[]    = '03' ;
    CHAR FSEND_PICM_STILL[]   = '04' ;
    
    DEFINE_CONSTANT//GET STATUS SEND CMDs
    
    CHAR FSEND_GET_PWR[]      = '0080' ;
    CHAR FSEND_GET_OSD[]      = '0180' ;
    CHAR FSEND_GET_LOCKS[]    = '0480' ;
    CHAR FSEND_GET_VID_IN[]   = '1080' ;
    CHAR FSEND_GET_ASPECT[]   = '1180' ;
    CHAR FSEND_GET_CNTRST[]   = '1380' ;
    CHAR FSEND_GET_BRIGHT[]   = '1381' ;
    CHAR FSEND_GET_COLOR[]    = '1382' ;
    CHAR FSEND_GET_TINT[]     = '1383' ;
    CHAR FSEND_GET_SHARP[]    = '1384' ;
    CHAR FSEND_GET_NOISE[]    = '1385' ;
    CHAR FSEND_GET_CTEMP[]    = '1386' ;
    CHAR FSEND_GET_PICMODE[]  = '138F' ;
    
    DEFINE_CONSTANT//Receive commands
    
    CHAR FRCV_PREFIX_OK[]     = '@S'  ; 
    CHAR FRCV_PREFIX_ERR[]    = '@E'  ;
    CHAR FRCV_REPLY_0[]       = 'S00' ;
    CHAR FRCV_REPLY_1[]       = 'S01' ;
    CHAR FRCV_REPLY_2[]       = 'S02' ;
    CHAR FRCV_REPLY_3[]       = 'S03' ;
    CHAR FRCV_REPLY_4[]       = 'S04' ;
    CHAR FRCV_REPLY_5[]       = 'S05' ;
    CHAR FRCV_REPLY_6[]       = 'S06' ;
    CHAR FRCV_REPLY_7[]       = 'S07' ;
    CHAR FRCV_REPLY_8[]       = 'S08' ;
    CHAR FRCV_REPLY_9[]       = 'S09' ;
    CHAR FRCV_REPLY_10[]      = 'S10';
    CHAR FRCV_REPLY_11[]      = 'S11';
    CHAR FRCV_REPLY_12[]      = 'S12';
    CHAR FRCV_REPLY_13[]      = 'S13';
    CHAR FRCV_REPLY_14[]      = 'S14';
    CHAR FRCV_REPLY_0E[]      = 'S0E' ;
    CHAR FRCV_REPLY_80[]      = 'S80' ;
    CHAR FRCV_ERR_REPLY_0[]   = 'E00' ;
    CHAR FRCV_ERR_REPLY_1[]   = 'E01' ;
    CHAR FRCV_ERR_REPLY_2[]   = 'E02' ;
    CHAR FRCV_ERR_REPLY_3[]   = 'E03' ;
    
    DEFINE_CONSTANT//BUTTONS INDEXES
    
    FBTN_PWR_OFF              = 1 ;
    FBTN_PWR_ON               = 2 ;
    FBTN_TGL_PU               = 47 ;
    
    BUTTON_EVENT[dvTP,nCH_BtnArry]
         
         {
         PUSH:
    	  {
    	  STACK_VAR INTEGER nBTN
    	  nBTN = GET_LAST(nCH_BtnArry)
    	  
    	  If (nFUJ_DeBug)
    	       {
    	       SEND_STRING 0,"'Fujitsu ',fnDEV_TO_STRING(BUTTON.INPUT.DEVICE),
    					     '-CHANNEL ',itoa(nCH_BtnArry[nBTN]),
    						  ' Line-<',ITOA(__LINE__),'>',CRLF" ;
    	       }
    	  if(sFUJ_Stat.PWR || nBTN == nCH_BtnArry[FBTN_PWR_ON ] || nBTN == nCH_BtnArry[FBTN_TGL_PU])
    	       {
    	       SWITCH(nBTN)
    		    {
    		    CASE 1: 	//POWER OFF
    			 {
    			 cFUJ_CMDQueue = "cFUJ_CMDQueue,FSEND_POFF,FUJ_QUEUE_DELIM" ;
    			 cFUJ_QueryQueue = "cFUJ_QueryQueue,FSEND_GET_PWR,FUJ_QUEUE_DELIM" ;
    			 }
    		    CASE 2:	//POWER ON
    			 {
    			 cFUJ_CMDQueue = "cFUJ_CMDQueue,FSEND_PON,FUJ_QUEUE_DELIM" ;
    			 cFUJ_QueryQueue = "cFUJ_QueryQueue,FSEND_GET_PWR,FUJ_QUEUE_DELIM" ;
    			 }
    

    How would I use this same logic to place my char array or constant definitions into my module but then call them from my main line?
  • viningvining Posts: 4,368
    mjones2620 wrote: »
    How would I use this same logic to place my char array or constant definitions into my module but then call them from my main line?

    You can pass constants to to module as a parameter if you create an array of constants or you can create an include file .axi of constants and #include MyModConstants.axi inside your module. They when the module is compiled it pulls in or includes the include file. It you have allot of constants to use in the main and module use the include but it there's just a couple then pass them into the mod as a constant array or element of a constant array.
Sign In or Register to comment.