Home AMX User Forum AMX General Discussion

Compiler directives in Arrays

I've never tried using the compiler directives in this manner before and since it worked I figured I'd post it.

This is a query array that I use to send a rolling query where I sequentially index through the array when on the device's page and comms are idle. Depending on equipment configuration in this case pool equipment some queries aren't necassary since they may or may not have a spa, heat or solar heating. This led me to try the compiler directives inside the query array to include only what would be necassary.
#DEFINE POOL_INCL_HEAT
#DEFINE POOL_INCL_SPA
//#DEFINE POOL_INCL_SOLAR_HEAT

DEFINE_VARIABLE //TX_POLLING_QUERY CMD_ARRY

CHAR nPOOL_LEN_QUERY_ARRY = 18 ;

CHAR cPOOL_QUERY_ARRY[][10]=

	  {
(*01*)	  'POOLTMP'	//
#IF_DEFINED POOL_INCL_SPA
(*02*)	  ,'SPATMP'	//
#END_IF			//
(*03*)	  ,'AIRTMP'	//
(*04*)	  ,'PUMPLO'	//
(*05*)	  ,'PUMPHI'	//
(*06*)	  ,'PUMP'	//
#IF_DEFINED POOL_INCL_SPA
(*07*)	  ,'SPA'	//
#END_IF			//
#IF_DEFINED POOL_INCL_HEAT
(*08*)	  ,'POOLSP'	//
(*09*)	  ,'POOLSP2'	//
#IF_DEFINED POOL_INCL_SPA
(*10*)	  ,'SPASP'	//
#END_IF			//
(*11*)	  ,'POOLHT'	//
(*12*)	  ,'POOLHT2'	//
#IF_DEFINED POOL_INCL_SPA
(*13*)	  ,'SPAHT'	//
#IF_DEFINED POOL_INCL_SOLAR_HEAT
(*14*)	  ,'SOLHT'	//
#IF_DEFINED POOL_INCL_SPA
(*15*)	  ,'SPASOLHT'	//
#END_IF			//
(*16*)	  ,'SOLPREF'	//
#IF_DEFINED POOL_INCL_SPA
(*17*)	  ,'SPASOLPREF' //
#END_IF			//
#END_IF			//
#END_IF			//
(*18*)	  ,'OPMODE'	//
  	  }
DEFINE_START    //SET IP if PROVIDED && initial values
     
     {
     nPOOL_LEN_QUERY_ARRY = LENGTH_ARRAY(cPOOL_QUERY_ARRY);

Now my array only contains queries that are needed specifically for this installation and I can minimze traffic. I was thinking it wasn't going to work but tried anyway and was pleasantly suprised.

Comments

  • ericmedleyericmedley Posts: 4,177
    Nice! very slick!
  • Don DeLongDon DeLong Posts: 43
    Wow, never in a million years would I have expected that to work. Very cool way to do this, and also minimizes array size to save memory allocation. I wouldn't expect that to make much difference in a single array like this, but if you had a list like this for every device, could add up fast.
  • ThorleifurThorleifur Posts: 58
    Where is the damn like button when you need one!
  • ppdkppdk Posts: 31
    Not quite a "like" button but something similar, is the small STAR icon underneath the user's signature in each post. ;)

    |
    |
    |
    V
  • Beyond #DEFINE

    On a side note, are you aware you can use more than just #DEFINE as compiler directives? Devices, Constants, Variables, Structure types, and DEFINE_CALLs all work as compiler directives. I often use this to test code in an include file that is dependent on a device being defined externally to the include:
    PROGRAM_NAME='IncludeFile'
    
    #IF_NOT_DEFINED vdvCOMM
    DEFINE_DEVICE
    	vdvCOMM = 33001:1:0;
    #END_IF
    
  • a_riot42a_riot42 Posts: 1,624
    I don't know. Looks like a lot of overhead to maintain and thus prone to hard to find bugs. It looks like you would need lots of commenting as well, and I keep comments at a minimum and try and write self commenting code. Its not easy to read, and would take a lot of looking to trace what is and what isn't in the array.

    I use compiler directives as little as I can get away with and that's almost never. Plus it just looks ugly and I hate having to read ugly looking code. If it were me I would break it up into different arrays like basic commands and extended commands or something similar. With Denon receivers for instance, they all have the same basic commands, but some have extras so I write one module that accommodates all of them without directives. If the command doesn't exist then it never gets sent and the feedback is parsed in a generic way. The module is a superset of all Denon commands, and the subsets use what they need and ignore the rest. Not sure if you wanted my opinion but there it is :)
    Paul
  • viningvining Posts: 4,368
    I agree it does make the code a bit messy but once a module is written and debugged you should rarrely ever need to go back into it unless the manufacturer changes its operation on newr devices. Like Denon does.

    I think having this at the begining of my code:
    #DEFINE POOL_INCL_HEAT
    #DEFINE POOL_INCL_SPA
    //#DEFINE POOL_INCL_SOLAR_HEAT
    #DEFINE POOL_INCL_AUX1
    #DEFINE POOL_INCL_AUX2
    //#DEFINE POOL_INCL_AUX3
    //#DEFINE POOL_INCL_AUX4
    //#DEFINE POOL_INCL_AUX5
    //#DEFINE POOL_INCL_AUX6
    #DEFINE POOL_INCL_AUTOFILL  
    
    Is neat and makes it real easy to configure and then these can be used to modify my array as posted or as I would typically use like this:

    In my Init buttons function that determines which buttons show based on config.
     #IF_NOT_DEFINED POOL_INCL_AUTOFILL
         fnPool_ProcessUI_CMD(iUI_Indx,"'^SHO-',itoa(POOL_VT_AUTOFILL),',0'");
         #END_IF     
         
         #IF_NOT_DEFINED POOL_INCL_SOLAR_HEAT
         fnPool_ProcessUI_CMD(iUI_Indx,"'^SHO-',itoa(POOL_VT_SOLHT),',0'");
         fnPool_ProcessUI_CMD(iUI_Indx,"'^SHO-',itoa(POOL_VT_SPASOLHT),',0'");
         fnPool_ProcessUI_CMD(iUI_Indx,"'^SHO-',itoa(POOL_VT_SOLPREF),',0'");
         fnPool_ProcessUI_CMD(iUI_Indx,"'^SHO-',itoa(POOL_VT_SPASOLPREF),',0'");
         #END_IF
         
         #IF_NOT_DEFINED POOL_INCL_AUX1
         fnPool_ProcessUI_CMD(iUI_Indx,"'^SHO-',itoa(POOL_VT_AUX1),',0'");
         #END_IF
         #IF_NOT_DEFINED POOL_INCL_AUX2
         fnPool_ProcessUI_CMD(iUI_Indx,"'^SHO-',itoa(POOL_VT_AUX2),',0'");
         #END_IF
         #IF_NOT_DEFINED POOL_INCL_AUX3
         fnPool_ProcessUI_CMD(iUI_Indx,"'^SHO-',itoa(POOL_VT_AUX3),',0'");
         #END_IF
         #IF_NOT_DEFINED POOL_INCL_AUX4
         fnPool_ProcessUI_CMD(iUI_Indx,"'^SHO-',itoa(POOL_VT_AUX4),',0'");
         #END_IF
         #IF_NOT_DEFINED POOL_INCL_AUX5
         fnPool_ProcessUI_CMD(iUI_Indx,"'^SHO-',itoa(POOL_VT_AUX5),',0'");
         #END_IF
         #IF_NOT_DEFINED POOL_INCL_AUX6
         fnPool_ProcessUI_CMD(iUI_Indx,"'^SHO-',itoa(POOL_VT_AUX6),',0'");
         #END_IF
    
    Or in my Update UI function (for new on page UIs) I can limit feedback to just what they need based on the buttons/config used.
    #IF_DEFINED POOL_INCL_AUTOFILL  
         fnPool_ProcessCHNL(iUI_Indx,POOL_BTN_AUTOFILL,nPoolAutoFill);
         #END_IF
         
         #IF_DEFINED POOL_INCL_AUX1     
         fnPool_ProcessCHNL(iUI_Indx,POOL_BTN_AUX1,sPool.sStatus.nAux[1]) ; 
         #END_IF
         #IF_DEFINED POOL_INCL_AUX2
         fnPool_ProcessCHNL(iUI_Indx,POOL_BTN_AUX2,sPool.sStatus.nAux[2]) ;
         #END_IF
         #IF_DEFINED POOL_INCL_AUX3
         fnPool_ProcessCHNL(iUI_Indx,POOL_BTN_AUX3,sPool.sStatus.nAux[3]) ;
         #END_IF
         #IF_DEFINED POOL_INCL_AUX4
         fnPool_ProcessCHNL(iUI_Indx,POOL_BTN_AUX4,sPool.sStatus.nAux[4]) ;
         #END_IF
         #IF_DEFINED POOL_INCL_AUX5
         fnPool_ProcessCHNL(iUI_Indx,POOL_BTN_AUX5,sPool.sStatus.nAux[5]) ;
         #END_IF
         #IF_DEFINED POOL_INCL_AUX6
         fnPool_ProcessCHNL(iUI_Indx,POOL_BTN_AUX6,sPool.sStatus.nAux[6]) ;
         #END_IF
         
         #IF_DEFINED POOL_INCL_HEAT
         fnPool_ProcessCHNL(iUI_Indx,POOL_BTN_POOLHT_ON,sPool.sStatus.nPoolHT == 1) ;
         fnPool_ProcessCHNL(iUI_Indx,POOL_BTN_POOLHT_OFF,sPool.sStatus.nPoolHT == 0) ;
         fnPool_ProcessCHNL(iUI_Indx,POOL_BTN_POOLHT2_ON,sPool.sStatus.nPoolHT2 == 1) ;
         fnPool_ProcessCHNL(iUI_Indx,POOL_BTN_POOLHT2_OFF,sPool.sStatus.nPoolHT2 == 0) ;
         #END_IF
         
         #IF_DEFINED POOL_INCL_SPA
         fnPool_ProcessCHNL(iUI_Indx,POOL_BTN_SPAHT_ON,sPool.sStatus.nSpaHT == 1) ;
         fnPool_ProcessCHNL(iUI_Indx,POOL_BTN_SPAHT_OFF,sPool.sStatus.nSpaHT == 0) ;
         #END_IF
         
         #IF_DEFINED POOL_INCL_SOLAR_HEAT
         fnPool_ProcessCHNL(iUI_Indx,POOL_BTN_SOLHT,sPool.sStatus.nSolHT) ; 
         fnPool_ProcessCHNL(iUI_Indx,POOL_BTN_SPASOLHT,sPool.sStatus.nSpaSolHT) ; 
         fnPool_ProcessCHNL(iUI_Indx,POOL_BTN_SOLPREF,sPool.sStatus.nSolPref) ; 	
         fnPool_ProcessCHNL(iUI_Indx,POOL_BTN_SPASOLPREF,sPool.sStatus.nSpaSolPref) ;
         #END_IF
    

    I don't have to regulate my parsing feedback since there are no buttons that can be pushed which don't coincide with the config and I'm not polling for any status that isn't part of the config.

    Yeah it's messy but I think the benefits out weigh the ugliness factor. The stuff above I really don't find as ugly as the array code that I originally posted.
  • a_riot42a_riot42 Posts: 1,624
    I'm not saying it won't work but compiler directives are for when you want the code pulled out before compilation due to excess memory usage, different processors, etc. You are using them instead of constants, so although it works, constants would be a better alternative imo. It isn't like compiling the extra unneeded commands will use too much memory, break the program if run on the wrong processor, are wrong endian, etc. You are using the directive mechanism for what constants are for, so its confusing, and since directives have global scope, somewhat dangerous.

    If you look at the Kaleidescape module they use directives to ignore the SATP code that uses far more memory, so it can be compiled without that code and that is a good reason to use them in that case. You are using them more as logic statements to build arrays, which to me is far less readable. If going this route wouldn't header files be better and then use directives to include the correct one depending on the project?
    Paul
  • viningvining Posts: 4,368
    They're not being used instead of constants at all. If I used constants everytime these sections of the code ran it would check the value of the constant to determine if the following code should run. Using compiler directives on these sections that aren't required for the config don't exist during runtime so they never need to be compared to a value to see if the code should run or not. How can something that doesn't exist be compared to something that does? :)
  • a_riot42a_riot42 Posts: 1,624
    vining wrote: »
    They're not being used instead of constants at all. If I used constants everytime these sections of the code ran it would check the value of the constant to determine if the following code should run. Using compiler directives on these sections that aren't required for the config don't exist during runtime so they never need to be compared to a value to see if the code should run or not. How can something that doesn't exist be compared to something that does? :)

    I get it now :)
    Paul
Sign In or Register to comment.