[comp.sys.mac.programmer] Millisecond timing on Mac II

carrier@sdics.ucsd.EDU (Mark Carrier) (09/07/88)

I am trying to get accurate millisecond timing on a Mac II.  I 
want to record subject reaction times where the responses are
keypresses.  Installing a task via the Time Manager seems the
most promising approach, where the task simply increments a
global counter every millisecond.  The only problem is that 
there does not seem to be a convenient way of making the task
be executed every millisecond.  Calling the routine PrimeTime
from within the task itself to reschedule its execution does
not work (the Mac crashes).

Does anybody know a convenient (or any) way of doing this?  Is
it possible?  If not, is there some other (perhaps lower-level) 
way of achieving millisecond timing?

Any and all suggestions are appreciated.  This timing problem
seems solvable on the Mac II, someone must have already done
such timing for some application?!!

				Mark Carrier

beard@ux1.lbl.gov (Patrick C Beard) (09/07/88)

In article <626@sdics.ucsd.EDU> carrier@sdics.UUCP (Mark Carrier) writes:
>
>I am trying to get accurate millisecond timing on a Mac II.  I 
>want to record subject reaction times where the responses are
>keypresses.  Installing a task via the Time Manager seems the
>most promising approach, where the task simply increments a
>global counter every millisecond.  The only problem is that 
>there does not seem to be a convenient way of making the task
>be executed every millisecond.  Calling the routine PrimeTime
>from within the task itself to reschedule its execution does
>not work (the Mac crashes).
>
>Does anybody know a convenient (or any) way of doing this?  Is
>it possible?  If not, is there some other (perhaps lower-level) 
>way of achieving millisecond timing?
>
>
>				Mark Carrier

I am using the Time Manager to do exactly what you describe, namely,
reinstalling myself to schedule some future event.  Here is a code
excerpt:

pascal void StepperInt()
{
	SetCurrentA5();		/* set up access to my globals */
	CurrentDirection=GridStepper->CurrentDirection;
	currentTime=INTERRUPT_PERIOD;	/* some constant time in milliseconds */
	PrimeTime(&TMStepperTask, currentTime);

	/* code ... */

	RestoreCurrentA5();	/* restore previous A5 */
}

SetCurrentA5() and RestoreCurrentA5() are routines I wrote in assembly 
language that use PC relative storage to store and retrieve the current
and my values of A5 to solve interrupt global access under multifinder.
A third routine, RememberOurA5() is called at application startup to
store A5 for later retrieval by the interrupt routine.  If there is
further interest I will post these routines, but they are easy enough
to implement.

The reason your calls to PrimeTime() at interrupt time were crashing is
probably because you weren't setting up access to your globals properly.

I hope this helps.

Patrick Beard
Lawrence Berkeley Laboratory
beard@ux1.lbl.gov

The reason you 

beard@ux1.lbl.gov (Patrick C Beard) (09/07/88)

By the way, you can use SetUpA5() and RestoreA5() if you aren't worried
about Multifinder compatibility.  The reason these won't work under MF is
that the low memory global, CurrentA5 (0x904), has a different value if
a different application is frontmost.  You have to keep your application's
A5 in a safe place.

Patrick Beard
Lawrence Berkeley Laboratory
beard@ux1.lbl.gov

lsr@Apple.COM (Larry Rosenstein) (09/07/88)

In article <947@helios.ee.lbl.gov> beard@ux1.lbl.gov (Patrick C Beard) writes:
>By the way, you can use SetUpA5() and RestoreA5() if you aren't worried
>about Multifinder compatibility.  The reason these won't work under MF is

Tech Note #208 warns about using these in some optimizing compilers.  These
routines push the old value of A5 on the stack, but some compilers (MPW 3.0
is sited) leave function parameters on the stack across multiple function
calls, which breaks these routines.

Instead they suggest using a couple of inline procedures that set A5 and
return its old value.  You simply save the old value in a local variable.

FUNCTION SetCurrentA5: LONGINT;
	INLINE $2E8D, $2A78, $0904;
{ returns A5 and sets A5 from CurrentA5 }

FUNCTION SetA5(newA5: LONGINT): LONGINT;
	INLINE $2F4F, $0004, $2A5F;
{ returns A5 and sets it based on the parameter }

As you said you can't use th value of CurrentA5 under MultiFinder.
Unfortunately, the TimeManager does not pass a poiner to your time request
to the routine, so you must store your application's A5 value in with the
code of your time manager routine.  

Then you can get the A5 value with a PC-relative reference and use SetA5 to
set the register.

		 Larry Rosenstein,  Object Specialist
 Apple Computer, Inc.  20525 Mariani Ave, MS 46-B  Cupertino, CA 95014
	    AppleLink:Rosenstein1    domain:lsr@Apple.COM
		UUCP:{sun,voder,nsc,decwrl}!apple!lsr

conybear@bruce.oz (Roland Conybeare) (09/08/88)

From article <626@sdics.ucsd.EDU>, by carrier@sdics.ucsd.EDU (Mark Carrier):
> 
> I am trying to get accurate millisecond timing on a Mac II.  I 
>
	Just a thought: LSC's profiler appears to do millisecond timing
so you might get a look at how it does it.

Roland Conybeare
(conybear@moncsbruce.oz)