getting the timing right
getting the timing right
- Subject: getting the timing right
- From: "Patrick S. Page-McCaw" <email@hidden>
- Date: Fri, 8 Dec 2000 20:06:01 -0800
I'm having trouble doing something I suspect AppleScript was not designed
to do. What I want to do is to flip an ADB I/O switch (BeeHive Inc) every
500 milliseconds. A few milliseconds error in flipping the switch is not a
problem, but 10s to 100s of milliseconds are a big problem. Consistency is
the most important issue. I flip the switch 50 times, then repeat this
several times after a wait. I want eventually to have a user initiated
start from within the running applet.
(Why am I doing this? I'm looking to see how smart fish are by tapping
their dish with a solenoid and measuring how fast they learn to ignore the
tapping.)
I am having two, I think, problems. ( 1.) If the script is run from
script editor, I can get very precise flips of the switch (501 +/- 1 msec).
If I run from a compiled stay open applet two things happen: the interval
increases by about 50 msec, no matter whether I want 500, 750 or 1000 msec
intervals and the error goes to over +/- 20 msec. Why does it take the
same code longer to run as an applet then from the Editor? Why the increase
in the error? I thought this might be due to priority, is there a way to
set this from within AppleScript? ( 2.) If the tapping run is repeated
only once the chance of an abberantly long interval is small, but if I
repeat the run more than once I always get errors of 200 or more
milliseconds showing up occaisonally (once or twice per run). I tried
calling idle directly before each tapping run, with the idle handler
returning a value greater than the total tapping run length, but this has
not helped. I guess a call to idle from the script does not pre-empt
System calls to the script to idle?
Again, what I want is the switch to be flipped every n +/- 3 milliseconds,
where n>300. I can wait for the system or whatever to do its stuff before
or after a run, but not during. How might I get consistency from the
machine?
I've tried (ineptly, I think) to have the idle handler tap then return when
the interval is up but this has not yet worked. I suspect that idle does
not expect to be called at such quick and precise intervals. Or I'm doing
something wrong.
I'm using a G4, OS 9.0.4.
This is what I've tried. Pardon the probably unusual construction, I never
took any programming classes (a youthful error).
----------------------
property gWatchFolder : "Fright:Desktop Folder:"
property gLogFileName : "test.csv"
global ISI
global theReps
set ISIlist to {200, 300, 500, 750, 1000}
set theReps to 50
repeat with checkISI in ISIlist
set ISI to checkISI
repeat 5 times
idle
set theISI of Stimulator to checkISI --milliseconds
set t0 to GetMilliSec
set x to {}
set y to {}
repeat theReps times
set end of x to GetMilliSec
tell Stimulator to SideTap()
end repeat
set prevItem to 0
repeat with theItem in x
set end of y to theItem - prevItem - checkISI
--gives time in millisec of error
set prevItem to theItem
end repeat
my LogEntry("")
my LogAListInCSV(rest of y)
end repeat
beep
end repeat
on idle
-- so the idea is to explicitly call an idle
-- at begin of every stim run with next idle
-- occurring after the next stim run
log theReps
return (ISI / 1000) * theReps * 1.1
end idle
script Stimulator
property theISI : 1
to SideTap()
set t0 to GetMilliSec
set ADBIO unit 1 port A channel 1 to high for seconds 0.1
delayIt(t0, theISI)
end SideTap
to UnderTap()
set t0 to GetMilliSec
set ADBIO unit 1 port A channel 3 to high for seconds 0.1
delayIt(t0, theISI)
end UnderTap
to toneEm()
set t0 to GetMilliSec
beep
delayIt(t0, theISI)
end toneEm
to delayIt(startTime, theISI)
repeat until (GetMilliSec) - startTime theISI
end repeat
end delayIt
end script
on LogEntry(someText)
try
set logFile to (gWatchFolder as text) & gLogFileName
set logRef to open for access (file logFile) with write
permission
--logRef
if logRef 0 then
-- this is one line
write FormatDateTime(current date) & ": " &
someText & return starting at eof to logRef
-- this is one line
close access logRef
end if
end try
end LogEntry
on LogAListInCSV(theList)
try
--if theList is not list then set theList to {theList}
set logFile to (gWatchFolder as text) & gLogFileName
set logRef to open for access (file logFile) with write
permission
if logRef 0 then
repeat with theItem in theList
write (theItem as text) & "," starting at
eof to logRef
end repeat
write return starting at eof to logRef
close access logRef
end if
on error
close access logRef
end try
end LogAListInCSV
on FormatDateTime(theDate)
set theDate to theDate as date
set dd to text -2 thru -1 of ("0" & theDate's day)
copy theDate to tempDate
set the month of tempDate to January
set mm to text -2 thru -1 of ,
("0" & 1 + (theDate - tempDate + 1314864) div 2629728)
set yy to text -1 thru -4 of ((year of theDate) as text)
set hh to time string of theDate
return (yy & mm & dd & " @ " & hh as text)
end FormatDateTime
Thanks,
Patrick