Home AMX User Forum AMXForums Archive Threads Residential Forum

basic programming question

so I'm finding myself buiding this program and i used power assign to number all my channels,etc but i did it so picked up off the last number used but now things are getting screwie bc if i need to add a button the numbers will all be out of order,etc.

and i'm looking at the netlinx code going, "man this is getting messy".So my question is. can someone tell me what your basic outline is when starting a fresh system is? is it:

-get the gui perfect
-then channel numbering
-then coding,etc?

bc what im doing is ive got this system now where none of the channels are in any order and im dublicating the tps for other rooms so im thinking is it better to give each source its own 100 channels like dvd=channels 100 to 200 , dvr= 201 to 301, cable box 2, 302 to 402, etc that way you have at least know what source has what and you also have some room to add buttons without screwing the numbering schedule?

i hope that all makes sense.

Comments

  • viningvining Posts: 4,368
    Usually we assign different devices to a different port on the TP. If you have ten devices with ten channels numbers 1-10 you would have 10001:1:0- 10001:10:0. Each TP port would be used for a single device and channel numbers can be re-used or not since they have different port addresses.

    Often I write the code first and then make a gui to match but it can be easier the other way around.
  • I usually try to do the UI first, and of course get that ok'd by the sales person and the customer before programming. Of course that does not always happen, but it's worth trying. Using virtual devices and ports to keep things in order to me is essential. I'll keep my main menus and power info on 1000:1:0, audio controls on 10001:2:0, dvd stuff on 10001:3:0 and so on.
  • jjamesjjames Posts: 2,908
    I may be in the minority on this - but I try to stay on one port for all my devices (unless it is a Fireball, ARQ, iPort or anything else that'd be intense to merge in.) For devices such as TVs, cable boxes, satellite receivers, A/V receivers, plasmas, am/fm tuners, etc. etc. - I use arrays.

    I've covered this in some detail here on the forums before, so I'll spare everyone the reading material and jump to the meat. Essentially how it works is you've got several "maps" (they can be variables because controlling which device could change on the fly.) For IR devices, it's super simple
    DEFINE_VARIABLE
    DEV IR_DEVICE[nAV_ZONE_MAX];
    
    In your routine in which you fire up your devices (I have a function named fnROOM_POWER), you assign which IR device you want to control for that zone. This is typically done with device arrays and using either the default assignment (the kitchen touch panel by default controls the kitchen cable box.) Usually using a short button event that selects the index of the device array of cable boxes (along with switching appropriate audio and video.) With the main button events I've defined a TRANSPORT_BTNS array of 1 though 99. (Can you think of any devices that use more than 100 commands?)

    Essentially, in the BUTTON_EVENT for the TRANSPORT_BTNS, you control a specific device based off of the zone's current source. You can use the AMX SNAPI or come up with your own (which is what I did.) For example: 1 = play, 2 = stop, 3 = pause, 44 = menu, 50 = exit, 55 = jump, 56 = DVR; most devices share common controls (DVRs, DVDs, VCRs, CD players, etc.) all use Play-Stop-Pause-FFWD-FRWD-Skip+ and Skip - (buttons 1-7) so they all get used in those sources.

    Here's a quick example of my button event that handles all sources, and controls for all devices. (If you wanted an EXTREMELY basic system - you'd have your "function" to turn things on and off, and a button event to select the source (and turn it off), and a button event to control the devices. So the way I do things, you coudl have 1 function, 3 button events and you'd be up and going. Here's what my device control BUTTON_EVENT looks like.
    BUTTON_EVENT[dv_TP,TRANSPORT_BTNS]			// TRANSPORT CONTROL
    {
    	PUSH:
    	{
    		STACK_VAR INTEGER nPANEL
    		STACK_VAR INTEGER nBTN
    		STACK_VAR INTEGER iSRC;
    		nPANEL = GET_LAST(dv_TP)
    		nBTN = BUTTON.INPUT.CHANNEL
    		
    		iSRC = nAV_ZONE_SOURCE[nPNL_AV[nPANEL]];
    		
    		TO[BUTTON.INPUT];
    		
    		// MANAGE DEVICE CONTROL
    		SWITCH(iSRC)
    		{
    			// MANAGE IR DEVICES
    			CASE nSRC_APPLE:
    			CASE nSRC_PIANO:
    			{
    				TO[IR_DEVICE[nPNL_AV[nPANEL]],nBTN]// CONTINUOUS IR OUTPUT 
    			}
    			
    			// MANAGE RS-232 DEVICES
    			
    			CASE nSRC_SAT:
    			{
    				IF(nSAT_CMDS_DUET[nBTN] < 900)
    					TO[vdv_SAT[nSAT_DEV_MAP[nPNL_AV[nPANEL]]],nSAT_CMDS_DUET[nBTN]]
    				ELSE
    					SEND_COMMAND vdv_SAT[nSAT_DEV_MAP[nPNL_AV[nPANEL]]],"'PASSTHRU-',SAT_CMD_PREFIX,cSAT_PASSTHRU_DUET[nSAT_CMDS_DUET[nBTN]-900]";
    			}
    			
    			// AM/FM
    			CASE nSRC_TUNER:
    			{
    				
    			}
    			
    			CASE nSRC_CD:
    			{
    				SEND_STRING dvCDC_HRT,"CD_COMMANDS[nBTN],CR";
    			}
    			
    			// Oppo Blu-Ray Player
    			CASE nSRC_BDP:
    			{
    				SEND_STRING dv_BDP[nBDP_DEV_MAP[nBDP_SELECTED[nPNL_AV[nPANEL]]]],"BDP_CMDS[nBTN],CR"
    			}
    		}
    	}
    }
    

    You could really do anything and still make it flexible. I would not recommend making things static.
    I.e.
    BUTTON_EVENT[dvTP_KIT,1]
    {
    	PUSH:
    	{
    		SWITCH(KitchenSource)
    		{
    			CASE Satellite:
    			{
    				TO[dvSAT_KIT,1]
    			}
    			
    			CASE DVD:
    			{
    				TO[dvDVD_KIT,1]
    			}
    			
    			// etc.
    		}
    	}
    }
    
    BUTTON_EVENT[dvTP_KIT,2]
    {
    	PUSH:
    	{
    		SWITCH(KitchenSource)
    		{
    			CASE Satellite:
    			{
    				TO[dvSAT_KIT,2]
    			}
    			
    			CASE DVD:
    			{
    				TO[dvDVD_KIT,2]
    			}
    			
    			// etc.
    		}
    	}
    }
    
    Side note, I from time to time have to deal with this type of coding; imagine 10 touch panels, and 55 button events each - and inside a switch / case for each source. If you have to go back and change all ten panels' play command - you've got 10 changes. Imagine you need to swap out an IR controlled DVD with a serial controlled DVD. 10 x 55 . . . do the math. Or, you could deal with something that's dependent on source selection other maps, and string arrays and make only 1 or two changes.

    This assumes though that you've modified any IR files to use a specific command template (1 - play, 2 - stop, etc.)

    Anyway - enough about code. As far as the order of getting it done. I go with GUI first (this way, I have a plan as to what I need to do with code instead of coding aimlessly or on the fly - and thing try to think how to fit it on the page, where it will go on the page and if I need popups or pages, or whatever! And you shouldn't have to start out fresh every single time. Once you have a flexible coding scheme in place, and a GUI that's easily customizable, but structurally the same - you should be able to deploy your code quickly. (Unless of course someone comes along, and "designs" the hardware layout to how they want it - and doesn't involve you in the process, then throws you 8 masters to control what 2 could do and you WANNA RIP YOUR HAIR OUT BECAUSE IT'S TAKING TOO MUCH TIME AND ARRRRRGH . . . umm - sorry.)

    So if there's anything you get out of this long post - do not make thing so dependent on each other that when you need to make a change that it messes everything else. Keep it flexible, but realize when you that things will "appear" to be more complicated. This takes time in getting used to (i.e. arrays within arrays pointing to other arrays.) Also, you could easily do this with structures as well, I just haven't gotten around to making a drastic change like that yet.

    Anyway - good luck and happy programming!
  • DHawthorneDHawthorne Posts: 4,584
    I find it helpful to break up channels by function. For example, I'll have an array defined like this for transport buttons: VOLATILE INTEGER nTransportButtons[] = {1, 2, 3, 4, 5, 6, 7, 8} ; and another VOLATILE INTEGER nMIscDeviceFunctions[] = {29 ... 99} (ellipsis for forum brevity). My button events use the array for a channel parameter, and a switch...case to determine what is called. That way, if future add-ons require me to stick an odd channel number in there, I just have to edit the array accordingly. It's far easier to manage if you have a bunch of smaller arrays rather than one whopper with every possible channel in it.
  • jjamesjjames Posts: 2,908
    DHawthorne wrote: »
    I find it helpful to break up channels by function. ... It's far easier to manage if you have a bunch of smaller arrays rather than one whopper with every possible channel in it.
    I had done this for a while, but became too much of a headache. I actually don't think it's easier to manage. If you've manage "all" the control channels effectively - it's simple to change (if need be.) Each device has their own command set be it an IR file or a string array for serial devices. Example:
    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+
    	,''				// 21          
    	,'!4SKPUP'		// 22	- SKIP UP
    	,'!4SKPDN'		// 23	- SKIP DOWN
    	,''				// 24
    	,''				// 25
    	,''				// 26
    	,'!4PWR01'		// 27	- POWER ON
    	,'!4PWR00'		// 28	- POWER OFF
    	,''				// 29
    	,''				// 30
    	,''				// 31
    	,''				// 32
    	,''				// 33
    	,''				// 34
    	,''				// 35
    	,''				// 36
    	,''				// 37
    	,''				// 38
    	,''				// 39
    	,''				// 40
    	,''				// 41
    	,''				// 42
    	,''				// 43
    	,''				// 44
    	,''				// 45
    	,''				// 46
    	,''				// 47
    	,''				// 48
    	,''				// 49
    	,''				// 50
    	,'!4DSC01'		// 51	- DISC 1
    	,'!4DSC02'		// 52	- DISC 2
    	,'!4DSC03'		// 53	- DISC 3
    	,'!4DSC04'		// 54	- DISC 4
    	,'!4DSC05'		// 55	- DISC 5
    	,'!4DSC06'		// 56	- DISC 6
    	,'!4DSCUP'		// 57	- DISC UP
    	,'!4DSCDN'		// 58	- DISC DOWN
    	,'!4RPT'			// 59	- REPEAT
    	,'!4RND'			// 60	- RANDOM
    }
    

    Now, if I had an IR file - they'd be mapped that way for me. I don't like having an IR lookup table, it takes too much time to configure from job to job in my opinion. I just want to slap something in and go and not have to think about which device uses which command index.

    Instead of however many categories you have (I'd guess 4 or 5), I think it's much easier to handle 1. If I have 10 sources, I manage only 10 switch/cases . . . as opposed to however many categories you have time 10.

    As the catchphrase goes in our industry: There are many ways to skin a cat.
Sign In or Register to comment.