Home AMX User Forum NetLinx Studio

Define_function

Hi, I finished programmer 2 about a year and half ago and only do AMX projects about every third month so becoming proficient has been a slow process. In my class we briefly went over define function but did not discuss it a whole lot or use one in class. I was wondering if anyone had some code handy that I could analyze to get a better feel for what context to use it. Forgive me but I havent been able to find my book from the class since my last move and in netlinx studios the definition is not very detailed. Any help is greatly appreciated.

Comments

  • ColzieColzie Posts: 470
    I use functions *extensively* in my programs. I like to explain it this way: if you have the exact same block of code in your program more than once, use a function. Duplicated code is a huge pet peeve of mine. Looking through someone else's program (or some of my early work) and seeing page after page of similar blocks of code repeated over and over again is painful to see.

    Here is a very simple example of a function:
    (*********************************************)
    (* INFO: Screen control                      *)
    (*                                           *)
    (*********************************************)
    define_function fn_screen (integer iCmd)
    {
    	switch(iCmd)
    	{
    		case SET_PWR_ON:
    		{
    			pulse[dv_RELAY, RELAY_SCREEN_DN]
    			[dv_TPs, TP_SCREEN_DN] = 1
    		}
    		
    		case SET_PWR_OFF:
    		{
    			pulse[dv_RELAY, RELAY_SCREEN_UP]
    			[dv_TPs, TP_SCREEN_UP] = 1
    		}
    	}
    }
    

    Some might say that creating a function for something as simple as pulsing a relay to drop a screen is overkill. I disagree. I can drop the screen with one line of code as needed (fn_screen (SET_PWR_ON)) throughout my program. Now let's say this particular screen only drops while the relay is held closed...I can change my function one time, and no matter how many times in my program I need to drop the screen, they all still work. If you hard code "pulse[dv_RELAY, RELAY_SCREEN_DN]" instead of using a function, you have to search through your code and replace it.

    This is just a very simple example, but it makes my point (hopefully!). I rarely control a device directly from a button push, rather I have a button push call a function to control a device (or send the command to a module). Early on I ran into too many times of needing to do "something", and putting it in a button push....only later needing to do that same "something" somewhere else. DO_PUSH is a hack (in most cases, in my opinion) to achieve the same result, creating a function is the more elegant solution.
  • jweatherjweather Posts: 320
    The function above could also be written as a define_call, which you may have used before. Aside from the different syntax (fn_screen() vs. CALL 'fn_screen'), functions also have the ability to return a value:
    // input: 0-64 output: 0-255
    define_function INTEGER scaleVolume(INTEGER vol) {
        return (vol*255)/64
    }
    

    This can be used in an expression like so: SEND_LEVEL dvTP, 1, scaleVolume(inputLevel)

    The principal is the same -- reduce duplicated code, especially when you might need to change that code in the future. Even if you only use it once, it lets you write self-documenting code by putting a name on that particular expression or calculation.
  • SCOTTYPSCOTTYP Posts: 32
    AHHH, thankyou both....The picture is getting a little clearer. Im going to try and re write some of a project I just did to get some practice. I work at a college so on slower days its always fun going back to some of my older programs and updating them with the tidbits I get from these forums.
  • jjamesjjames Posts: 2,908
    And of course you can call multiple functions during a command. Such as . . .

    SEND_COMMAND dv_TP[fnGET_PANEL(nZone)], "'@TXT-',GET_LAST(nPresets),',',fnSavePreset(GET_LAST(nPresets))"

    Where blue words are system functions and the red ones would be user defined . . . just giving a visual reference.

    And Colzie - I completely agree with the modifying once and forget about it idea, rather than searching through code and looking for your PULSE command. Good point!
  • Data from Function to a Structure

    This post has been very helpful with explanations of functions. What I am having problems with is getting data out of the function, assigining it to a structure, and then using that data to do something. I was trying to do something simple like add two numbers and then do a SEND_LEVEL with the result for practice. The example in the book is not very helpful. This is my function:
    DEFINE_FUNCTION TestFunction()
    {
      LOCAL_VAR FirstNumber
      FirstNumber = FirstNumber + 2
    }
    

    I know I have to define a structure and then use the dot operator to start assigning values from the function, but my values never change. I don't use functions very often, but when I do, I usually follow this format:
    DEFINE_FUNCTION INTEGER TestFunction(INTEGER VALUE)
    {
      LOCAL_VAR RESULT
      RESULT = VALUE + 2
      RETURN RESULT  
    }
    
    DEFINE EVENT
    
    BUTTON_EVENT[dvTP,1]
    {
      PUSH:
              {
                   nTEST = TestFunction(2)
              }
    }
    

    Doing it that way, a press of TP 1 will change nTest to 4. I guess I am missing a step somewhere while trying to pass and and use data from a structure. Any help with that would be much appreciated. Thanks in advance.
  • Spire_JeffSpire_Jeff Posts: 1,917
    Here is a sample, but I warn you that I am just writing this in the post, I am not using the compiler to test it, so there could be a few typos. :) The concept should be sound tho.
    define_type
    structure _sTest{
      char sName[25]
      char sData1[50]
      char sData2[50]
      integer nValue1
      integer nValue2
      integer nValueArray[10]
    }
    
    define_variable
    _sTest uTest
    _sTest uTestArray[50]
    
    define_function integer fnDoubleValue(integer value){
      return (value*2);
    }
    
    define_function integer fnRandomMultiply(integer value){
      return (value*(random_number(10)+1));
    }
    define_function char[25] fnRandomName(){
      stack_var char names[5][25];
      names[1] = 'Joe Bob';
      names[2] = 'Bobby Sue';
      names[3] = 'Tommy Lee';
      names[4] = 'John';
      names[5] = 'Cindy';
    
      return names[Random_Number(5)+1];
    }
    define_function fnPopulateTest(){
    		stack_var integer x;
    		uTest.nValue1 = random_number(200);
    		uTest.nValue2 = fnDoubleValue(uTest.nValue1);
    		uTest.nValueArray[1] = random_number(10);
    		for(x=2;x<=length_array(uTest.nValueArray);x++){
    			uTest.nValueArray[x] = fnRandomMultiply(uTest.nValueArray[x-1])
    		}
    		uTest.sData1 = "'Record created at:',time";
    		uTest.sData2 = "'Record created on:',date";
    	
    }
    
    define_event
    button_event[dvTp,1]{
      Push:{
    		stack_var integer x;
    		for(x=1;x<=length_array(uTestArray);x++){
    			fnPopulateTest();
    			uTestArray[x] = uTest;
    		}
      }
    }
    button_event[dvTp,2]{
    	Push:{
    		stack_var integer x;
    		x = random_number(50)+1;
    		send_string 0,"'#Random Record Number ',itoa(x),'#'"
    		send_string 0,"'Name:',uTestArray[x].sName";
    		send_string 0,"uTestArray[x].sData1";
    		send_string 0,"uTestArray[x].sData2";
    		send_string 0,"'Value1:',itoa(uTestArray[x].nValue1)";
    		send_string 0,"'Value2:',itoa(uTestArray[x].nValue2)";
    		send_string 0,"'Value Array:',itoa(uTestArray[x].nValueArray[1],',',
    																	itoa(uTestArray[x].nValueArray[2],',',
    																	itoa(uTestArray[x].nValueArray[3],',',
    																	itoa(uTestArray[x].nValueArray[4],',',
    																	itoa(uTestArray[x].nValueArray[5],',',
    																	itoa(uTestArray[x].nValueArray[6],',',
    																	itoa(uTestArray[x].nValueArray[7],',',
    																	itoa(uTestArray[x].nValueArray[8],',',
    																	itoa(uTestArray[x].nValueArray[9],',',
    																	itoa(uTestArray[x].nValueArray[10]";
    																	
    	}                                                        
    }
    
    

    Hopefully this addresses the topics you wanted.

    Jeff
  • GSLogicGSLogic Posts: 562
    This is a good example for many things!

    I know Jeff didn't test this but at a glance (and I could be wrong), I don't think button PUSH dvTp,1 will work. I seem to remember you can't get an array_length form a defined structure. You could just change the FOR loop max "length_array(uTestArray)" to a number for testing.

    Spire_Jeff wrote: »
    define_event
    button_event[dvTp,1]{
      Push:{
    		stack_var integer x;
    		for(x=1;x<=length_array(uTestArray);x++){
    			fnPopulateTest();
    			uTestArray[x] = uTest;
    		}
      }
    }
    
Sign In or Register to comment.