Home AMX User Forum AMXForums Archive Threads Tips and Tricks

DEFINE_CALL with parameters

bthbth Junior MemberPosts: 1
I have had a very bad experience with the DEFINE_CALL. I was supposing it worked the same as functions in other languages. So when i wrote a define call for rooms that could be combined, i was using a parameter for the room like this:

DEFINE_CALL 'SET_PROJECTOR' ( P_ROOM, P_CMD )

My idea was to use the call for each room with different parameters but till my surprise only the last call was always doing its work. This happened only when i was using waits in the defne call. So i recognised that the last define_call always cancelled all waits of the previous called!!!

Do you know a technology to work it around, let me know.

Comments

  • jjamesjjames Just another dude Posts: 2,906
    Can you post the entire call or at least a watered down version of it if you're protective of your code? Also, careful of using WAITs in SWITCH..CASES in DEFINE_CALLs or DEFINE_FUNCTIONS. Use a SELECT..ACTIVE instead - see tech note #736
  • Chip MoodyChip Moody Junior Member Posts: 727
    bth wrote:
    This happened only when i was using waits in the defne call. So i recognised that the last define_call always cancelled all waits of the previous called!!!

    There weren't any waits being cancelled. When your wait was called, you essentially qued up a block of code, saying "please wait x amount of time before running this code".

    Your call was only capable of referencing ONE room variable at a time. Look at this:

    CALL 'SET_PROJECTOR' (ROOM_A, VID_IN_CMD)
    CALL 'SET_PROJECTOR' (ROOM_B, VID_IN_CMD)
    CALL 'SET_PROJECTOR' (ROOM_C, VID_IN_CMD)

    If the code in your call for handling the video input command is inside a WAIT statement and references P_ROOM, just think about it a bit - by the time the wait (which is only qued up ONCE when the above three lines of code are run) expires, P_ROOM can/will ONLY be equal to ROOM_C.

    I.E., by the time the wait expires, P_ROOM has already gone from being equal to ROOM_A to ROOM_B and finally to the last value it was set to - ROOM_C.

    What you >need< is a WAIT with a variable name definition - which we don't have. :(

    One solution is to have a SELECT-ACTIVE block for each possible room value in your call, with a different wait block inside each ACTIVE segment. Inelegant, and kinda goes against part of the reason to have subroutines in the first place, but it would work.

    I'm thinking that there is a more elegant solution, but at the moment it's not coming to me...

    - Chip
  • veraviewveraview Junior Member Posts: 44
    Chip's got it right... with waits involved its possible to change the values of variables passed into the WAIT list after you've invoked the call in mainline. You can't create "instances" of a DEFINE_CALL, though wouldn't it be great if you could!
  • Spire_JeffSpire_Jeff Formerly Caffeinated Programmer Posts: 1,917
    To accomplish this, you could create a buffer for the commands and a timeline to check the queue. Something like:

    DEFINE_CONSTANT
    INTEGER nNUM_PROJECTORS = 3 //Number of projectors
    INTEGER nNUM_CMDS = 25 //Number of Commands to queue
    INTEGER nNUM_CHARS_IN_CMD = 10 //Max Number of characters in a single command string
    LONG lPROJ_TIMELINE = 1
    
    
    DEFINE_VARIABLE
    VOLATILE DEV dvPROJECTORS[nNUM_PROJECTORS] = {dvPROJ1,dvPROJ2,dvPROJ3}
    VOLATILE CHAR sCMD_QUEUE[nNUM_PROJECTORS][nNUM_CMDS][nNUM_CHARS_IN_CMD]
    VOLATILE INTEGER nCUR_CMD_PTR[nNUM_PROJECTORS]
    VOLATILE INTEGER nINSERT_CMD_PTR[nNUM_PROJECTORS]
    LONG lPROJ_TL_DELAY[] = {100,100,100,100,100}
    
    
    DEFINE_FUNCTION INTEGER SET_PROJ (INTEGER nPROJ, CHAR sCMD[nNUM_CHARS_IN_CMD])
    (* SEND_TP_CMD Function returns:
          0 if everything was handled properly
          1 if Queue was full
          
    *)
    {
       IF(DEBUG)
          SEND_STRING 0,"'COMMAND QUEUED: Projector = ',ITOA(nPROJ),' CMD = ',sCMD"
     
    		IF(TIMELINE_ACTIVE(lPROJ_TIMELINE))// Store command in queue if another command is currently being processed.
    			 {
    				 IF(!(nCUR_CMD_PTR[nPROJ] == 1 + ( nINSERT_CMD_PTR[nPROJ] % nNUM_CMDS)))
    					{
    					 nINSERT_CMD_PTR[nPROJ] = 1 + ( nINSERT_CMD_PTR[nPROJ] % nNUM_CMDS)  //Increase queue insertion point to next place unless we have reached max queue size 
    					 sCMD_QUEUE[nPROJ][nINSERT_CMD_PTR[nPROJ]] = sCMD
    					 
    					}  
    				 ELSE
    					{
    					 SEND_STRING 0,"'*********** Projector ',ITOA(nPROJ),' Command Queue is full ************ CMD:',sCMD"
    					 RETURN 1
    					}
    					
    			 } 
    		ELSE
    			 {
    					 nINSERT_CMD_PTR[nPROJ] = 1 + ( nINSERT_CMD_PTR[nPROJ] % nNUM_CMDS)  //Increase queue insertion point to next place unless we have reached max queue size 
    					 sCMD_QUEUE[nPROJ][nINSERT_CMD_PTR[nPROJ]] = sCMD
    					 TIMELINE_CREATE(lPROJ_TIMELINE,lPROJ_TL_DELAY,5,TIMELINE_RELATIVE, TIMELINE_REPEAT)
    			 }  
    		
    RETURN 0   
    
    }
    
    DEFINE_EVENT
    TIMELINE_EVENT[lPROJ_TIMELINE]
    {
    STACK_VAR INTEGER X 
    STACK_VAR INTEGER KILL_TL
    
    KILL_TL = 1
    
    		FOR(x=1;x<=nNUM_PROJECTORS;x++)
    			{
    				IF(!(nCUR_CMD_PTR[x]==nINSERT_CMD_PTR[x]))
    					{
    						nCUR_CMD_PTR[x] = 1 + (nCUR_CMD_PTR[x] % nNUM_CMDS)    //Point at first command to process 
    						SEND_STRING dvPROJECTORS[x],sCMD_QUEUE[x][nCUR_CMD_PTR[x]]
    						IF(DEBUG)
    							SEND_STRING 0,"'COMMAND SENT: Projector = ',ITOA(x),' Command = ',sCMD_QUEUE[x][nCUR_CMD_PTR[x]])
    					}
    				KILL_TL = KILL_TL && (nCUR_CMD_PTR[x]==nINSERT_CMD_PTR[x])	
    			}
    		IF (KILL_TL)           //Terminate queue processing if no more commands
    			TIMELINE_KILL(lPROJ_TIMELINE)
    		
    } 
    
    

    Now this might not be fully functional as I am hungry and I just quickly adapted some code I had to fit your situation, but hopefully this demostrates my point. If you have any further questions, or if something doesn't make sense, feel free to ask me.

    Jeff

    P.S.
    If all of the projectors share a common bus, you could use TIMELINE.SEQUENCE as opposed to the for loop for queue processing (still need to check all projectors with the for loop to decide if the timeline is still needed)

    Hope this helps and it makes as much sense in typed form as it does in my head at the moment
Sign In or Register to comment.