Home AMX User Forum AMXForums Archive Threads AMX Hardware

Strange Occurance

Good Morning,

I'm having some problems with code not executing correctly the first time it is executed.

In the function below, the first time this is called after a reboot, the "Wait nClipLength[nClip] 'ClipResetWait';" does not execute properly. I get the error, and the Wait is effectively set to 0:

Ref Error ^NCLIPLENGTH Index 0 Line=333
GetNumber - Error 1 Tk=0x0000

Define_Function PlayClip (Integer nUnit, Integer nClip)
{
	// Make sure the Music Track is Unmuted
	Send_Command vdXframe,"'SETA1-255'";
	
	// Send Clip to AR3000
	ml_AR3000_PLAY_CLIP (dvMidi, nUnit, nClip);
	
	If(nUnit = nShowUnit);
	{
		// Cancel Pending Waits
		CancelWaits ();
		
		Send_String 0,"'PlayClip Wait = ',Itoa(nClipLength[nClip])";
		Wait nClipLength[nClip] 'ClipResetWait';
		{
			nCurrClip = 0;
			Send_String 0,"'ClipResetWait Executed'";
		}
		
		// Set the current Clip number
		nCurrClip = nClip;
	}
	
	Send_String 0,"'Playing Roland #',Itoa(nUnit),', Clip ',Itoa(nClip)";

	Return;
}

All subsequent calls to this function execute properly, and the wait is set correctly. I've verified that the proper values are being passed by the Send_String 0's. The correct track plays back, so I know that the nClip and nUnit are being passed correctly.

Has anyone run into anything similar or have any thoughts?

Thanks,

--D

Comments

  • dchristodchristo Posts: 177
    Sorry, forgot to mention this is an NI-700 with current non-Duet firmware and the latest version of Studio.

    --D
  • dchristodchristo Posts: 177
    I actually added the semi-colons as part of the troubleshooting. The behaviour is the same with and without them.

    --D
  • DHawthorneDHawthorne Posts: 4,584
    I don't know this for a fact, but my first thought is that your CancelWaits() function is not actually firing until the function it is in is finished, effectively cancelling it before it has had time to fire. Depending on how you are calling the functions, this may not happen on subsequent passes. WAITs are odd beasts, and not really good for situations that require critical timing, and get queued in mainline rather than firing when called; you may want to rewrite this with a timeline.
  • Joe HebertJoe Hebert Posts: 2,159
    dchristo,

    I ?think? you found a bug. I can verify the same strange occurrence on an NI-700 with the latest DUET firmware.

    I can?t explain it but I did find a clue that might help to solve the problem. If you do the following the error will disappear.

    Add these two lines to the top of your function:

    LOCAL_VAR INTEGER nLocalCopy
    nLocalCopy = nClip

    And replace:
    Wait nClipLength[nClip] 'ClipResetWait'

    With:
    Wait nClipLength[nLocalCopy] 'ClipResetWait'

    You shouldn?t have to do this (at least not for any reasons that I?m aware of) but making a local copy eliminates the error the first time the function is called.
  • Joe Hebert wrote:
    dchristo,

    I ?think? you found a bug. I can verify the same strange occurrence on an NI-700 with the latest DUET firmware.

    I can?t explain it but I did find a clue that might help to solve the problem. If you do the following the error will disappear.

    Add these two lines to the top of your function:

    LOCAL_VAR INTEGER nLocalCopy
    nLocalCopy = nClip

    And replace:
    Wait nClipLength[nClip] 'ClipResetWait'

    With:
    Wait nClipLength[nLocalCopy] 'ClipResetWait'

    You shouldn?t have to do this (at least not for any reasons that I?m aware of) but making a local copy eliminates the error the first time the function is called.

    Good call Joe.

    Since the value of nClip must be available to the WAIT as a time parameter it is nul (zero index error) outside the function when the WAIT list is evaluated. I would not consider this a bug. By assigning the varaible passed into the function to a local variable insures that the time parameter is available to the WAIT.

    I was also going to ask whether the array nClipLength[] was declared as an integer, but I don't think it makes any difference.

    From NetLinx help
    WAIT
    This keyword is used to delay execution of one or more statements for a
    specified period of time. The syntax is:
    
    WAIT time ['[<name>']
    {
       (* wait statements *)
    }
    
    The NetLinx interpreter accepts any type of number 
    (including Floats and Doubles) for WAIT times but it casts them to an
    unsigned 32-bit number, i.e. a long. 
    
    So the max wait time 2^32 or 4294967295 100th's of a second, 
    as written in code:
    
    WAIT 42949672l9.5 // wait ~1.36 years
    {
      // do something a long time from now
    }
    
  • Joe HebertJoe Hebert Posts: 2,159
    B_Clements wrote:
    Since the value of nClip must be available to the WAIT as a time parameter it is nul (zero index error) outside the function when the WAIT list is evaluated.
    The variable is in scope (I believe Netlinx is in error) and I will post code to show that.
    B_Clements wrote:
    I would not consider this a bug.
    I do consider this to be a bug. (At least on an NI-700 with the latest DUET firmware ? I can?t confirm any other NI-xxxx series)

    After doing some testing I?ve concluded the following:

    1) Anytime you pass a variable as a parameter into a FUNCTION (or a CALL) and that variable is used as the delay time for a WAIT, the WAIT will NOT execute properly the FIRST time around. All subsequent calls will work.

    2) If you make a local copy of said variable in statement 1, all calls to the FUNCTION will work properly. (the local copy ?shouldn?t? be necessary but it is)

    3) If an index into an INTEGER ARRAY (that has a length) is used for the parameter a run-time error will occur the first go around.

    4) If you pass an INTEGER as a parameter a run-time error will NOT occur. However, the WAIT does NOT execute properly the first time.

    5) If a global variable is used as a delay time for a WAIT inside a FUNCTION, the WAIT will execute properly if that variable was NOT passed in as a parameter.

    Here is the code that I used to verify the above conclusions:
    DEFINE_DEVICE
    
    dvTP			= 10001:1:0
    
    DEFINE_VARIABLE
    
    INTEGER nDelays[] 	= {50,100,150,200}
    INTEGER nDelay 	= 50
    INTEGER nIndex		= 1
    
    //Calling this function the very first time WILL cause a runtime error
    //and the 5 second WAIT will NOT execute properly. All subsequent calls work correctly.
    DEFINE_FUNCTION fnArrayDelayTest (INTEGER nDelayIndex) {
    		
       SEND_STRING 0,"'Enter ArrayDelayTest. Wait = ',ITOA(nDelays[nDelayIndex])"
       WAIT nDelays[nDelayIndex] SEND_STRING 0,"'Executed ArrayDelayTest'"
       SEND_STRING 0,"'Exit ArrayDelayTest.'"
    
    }
    
    //Calling this function the very first time will NOT cause a runtime error
    //however the 5 second WAIT will NOT execute properly. All subsequent calls work correctly.
    DEFINE_FUNCTION fnIntegerDelayTest (INTEGER nDelayTime) {
    		
       SEND_STRING 0,"'Enter IntegerDelayTest. Wait = ',ITOA(nDelayTime)"
       WAIT nDelayTime SEND_STRING 0,"'Executed IntegerDelayTest.'"
       SEND_STRING 0,"'Exit IntegerDelayTest '"
    
    }
    
    //Calling this function works every time when a local copy of the parameter is used.
    DEFINE_FUNCTION fnArrayDelayTest2 (INTEGER nDelayIndex) {
    
       LOCAL_VAR INTEGER copy
       
       copy = nDelayIndex
    		
       SEND_STRING 0,"'Enter ArrayDelayTest2. Wait = ',ITOA(nDelays[nDelayIndex])"
       WAIT nDelays[copy] SEND_STRING 0,"'Executed ArrayDelayTest2'"
       SEND_STRING 0,"'Exit ArrayDelayTest2.'"
    
    }
    
    //Calling this function that doesn't pass the delay time in works every time
    DEFINE_FUNCTION fnDelayTest () {
    		
       SEND_STRING 0,"'Enter DelayTest. Wait = ',ITOA(nDelay)"
       WAIT nDelay SEND_STRING 0,"'Executed DelayTest'"
       SEND_STRING 0,"'Exit DelayTest.'"
    
    }
    
    
    DEFINE_EVENT
    
    //run-time error fist time and WAIT not correct
    BUTTON_EVENT[dvTP,1] {
    
       PUSH: {
          fnArrayDelayTest(nIndex)
       }
    }
    
    //no run-time error, however, WAIT will not be correct the first time
    BUTTON_EVENT[dvTP,2] {
    
       PUSH: {
          fnIntegerDelayTest(nDelay)
       }
    }
    
    //works every time
    BUTTON_EVENT[dvTP,3] {
    
       PUSH: {
          fnArrayDelayTest2(nIndex)
       }
    }
    
    // works every time
    BUTTON_EVENT[dvTP,4] {
    
       PUSH: {
          fnDelayTest()
       }
    }
    
    //works every time
    BUTTON_EVENT[dvTP,5] {
    
       PUSH: {
          SEND_STRING 0, 'Enter BUTTON_EVENT Delay.'
          WAIT nDelays[nIndex] SEND_STRING 0,"'Executed BUTTON_EVENT Delay.'"
          SEND_STRING 0, 'Exit BUTTON_EVENT Delay'
       }
    }
    

    And here is the output from above code:

    Button 1 ? The first time
    Line 1 :: Enter ArrayDelayTest. Wait = 50 - 01:54:43
    Line 2 :: Ref Error ^NDELAYS Index 0 Line=22 - 01:54:43
    Line 3 :: GetNumber - Error 1 Tk=0x0000 - 01:54:43
    Line 4 :: Exit ArrayDelayTest. - 01:54:43
    Line 5 :: Executed ArrayDelayTest - 01:54:43 (NO DELAY)

    Button 1 ? The second time and all other times
    Line 6 :: Enter ArrayDelayTest. Wait = 50 - 01:54:47
    Line 7 :: Exit ArrayDelayTest. - 01:54:47
    Line 8 :: Executed ArrayDelayTest - 01:54:52

    Button 2 ? The first time
    Line 9 :: Enter IntegerDelayTest. Wait = 50 - 01:54:54
    Line 10 :: Exit IntegerDelayTest - 01:54:54
    Line 11 :: Executed IntegerDelayTest. - 01:54:54 (NO DELAY)

    Button 2 ? The second time and all other times
    Line 12 :: Enter IntegerDelayTest. Wait = 50 - 01:54:58
    Line 13 :: Exit IntegerDelayTest - 01:54:58
    Line 14 :: Executed IntegerDelayTest. - 01:55:03

    Button 3 ? All times
    Line 15 :: Enter ArrayDelayTest2. Wait = 50 - 01:55:04
    Line 16 :: Exit ArrayDelayTest2. - 01:55:04
    Line 17 :: Executed ArrayDelayTest2 - 01:55:09

    Button 4 ? All times
    Line 18 :: Enter DelayTest. Wait = 50 - 01:55:10
    Line 19 :: Exit DelayTest. - 01:55:10
    Line 20 :: Executed DelayTest - 01:55:15

    Button 5 ? All times
    Line 21 :: Enter BUTTON_EVENT Delay. - 01:55:18
    Line 22 :: Exit BUTTON_EVENT Delay - 01:55:18
    Line 23 :: Executed BUTTON_EVENT Delay. - 01:55:23


    It doesn?t matter what order the buttons are pushed. The results will be the same.
  • dchristodchristo Posts: 177
    Joe,

    Thanks for the testing and verification. I haven't had a chance to try your suggestion yet, but I'll try this afternoon. I also plan to give tech support a call to let them know about this. Would you mind if I pass along your testing information to them?

    Also, I also tried this on a ME260 master with the same results. I didn't look at the firmware that's in it, but I would guess it's at least a year old. I'll check this afternoon.


    Thanks,

    --D
  • Very Interesting

    Joe,

    The second pass through the function does not produce the zero index error! Very interesting indeed! This would lead me to believe that the number associated with the WAIT is somehow retained after the first pass through the WAIT queue.

    If you get the opportunity, change (increment) the WAIT time passed into the function each subsequent button press and see if it uses the previous value or the new value.

    Brian
  • Joe HebertJoe Hebert Posts: 2,159
    dchristo wrote:
    I also plan to give tech support a call to let them know about this. Would you mind if I pass along your testing information to them?
    Please do, that?s what it?s here for. Let us know how the story ends.
  • Joe HebertJoe Hebert Posts: 2,159
    Good call, Brian
    B_Clements wrote:
    If you get the opportunity, change (increment) the WAIT time passed into the function each subsequent button press and see if it uses the previous value or the new value.
    I changed:
    BUTTON_EVENT[dvTP,1] {
    
       PUSH: {
          fnArrayDelayTest(nIndex)
       }
    }
    
    To this:
    BUTTON_EVENT[dvTP,1] {
    
       PUSH: {
          fnArrayDelayTest(nIndex)
          nIndex++
          IF (nIndex > LENGTH_ARRAY(nDelays)) nIndex=1
       }
    }
    

    And sure enough the WAIT time that gets retained is from the previous call to the function.

    Here are the results:

    Button 1 ? First Time
    Line 1 :: Enter ArrayDelayTest. Wait = 50 - 10:53:35
    Line 2 :: Ref Error ^NDELAYS Index 0 Line=22 - 10:53:35
    Line 3 :: GetNumber - Error 1 Tk=0x0000 - 10:53:35
    Line 4 :: Exit ArrayDelayTest. - 10:53:35
    Line 5 :: Executed ArrayDelayTest - 10:53:35 (NO DELAY)

    Button 1 ? Second Time
    Line 6 :: Enter ArrayDelayTest. Wait = 100 - 10:53:39
    Line 7 :: Exit ArrayDelayTest. - 10:53:39
    Line 8 :: Executed ArrayDelayTest - 10:53:44 (DELAY is 50 NOT 100)

    Button 1 ? Third Time
    Line 9 :: Enter ArrayDelayTest. Wait = 150 - 10:53:45
    Line 10 :: Exit ArrayDelayTest. - 10:53:45
    Line 11 :: Executed ArrayDelayTest - 10:53:55 (DELAY is 100 NOT 150)


    Button 1 ? Fourth Time
    Line 12 :: Enter ArrayDelayTest. Wait = 200 - 10:53:58
    Line 13 :: Exit ArrayDelayTest. - 10:53:58
    Line 14 :: Executed ArrayDelayTest - 10:54:13 (DELAY is 150 NOT 200)


    Button 1 ? Fifth Time
    Line 15 :: Enter ArrayDelayTest. Wait = 50 - 10:54:16
    Line 16 :: Exit ArrayDelayTest. - 10:54:16
    Line 17 :: Executed ArrayDelayTest - 10:54:36 (DELAY is 200 NOT 50)
  • Thank you for testing this.

    Joe,

    I believe your deserve a hearty handshake, pat on the back, and the warm glow of victory. ;)


    Dave,

    Did you forward this thread to AMX tech support, or should I?
  • dchristodchristo Posts: 177
    Brian,

    I have not called TS yet. It will probably be tomorrow before I have a chance. Please feel free to jump in if you'd like.

    Thanks,

    --D
  • Joe HebertJoe Hebert Posts: 2,159
    Brian wrote:
    Joe,
    I believe your deserve a hearty handshake, pat on the back, and the warm glow of victory. ;)
    Can I trade all that stuff in for some AMX equipment? :)
  • dchristo wrote:
    Brian,

    I have not called TS yet. It will probably be tomorrow before I have a chance. Please feel free to jump in if you'd like.

    Thanks,

    --D

    I just sent AMX support a link to this thread. I will follow up tomorrow.

    Dave, thanks for getting this started.
  • Joe Hebert wrote:
    Can I trade all that stuff in for some AMX equipment? :)

    I have an extra IR emitter in my desk drawer you can have.
  • Thanks all for your investigation. I'll get this sent up the chain.
Sign In or Register to comment.