home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Datafile PD-CD 1B
/
DATAFILE_PDCD1B.iso
/
_pocketbk
/
pocketbook
/
001
/
geteva_zip
/
GETEVA.DOC
next >
Wrap
Text File
|
1992-06-24
|
6KB
|
151 lines
Comments on geteva.opl
======================
This program demonstrates:
* An asynchronous form of GETEVENT
* How to keep a clock ticking over on the screen, once each
second, that measures only time in foreground (and only time when the
machine is switched on), without burning round in a continuous loop
* At the same time, the program is ready to respond at once to
any keypresses received
* How to peek the system time to within 1/32 of a second.
The program can also be viewed simply as an example of asynchronous
i/o, iowait, status words, and iosignal. These techniques allow very
powerful results. For general background to these techniques, see in
the first instance the chapter "Fundamental Programming Guidelines"
in the "General Programming Manual" of SDK 1.10. (This is written
for C programmers, but all the same concepts carry over into Opl.)
How the clock updates
---------------------
The clock starts at "0:00" and ticks over once each second.
Unfortunately, there are no flags for GCLOCK to achieve this (these
system clocks always display an "hours" field, and can only have
their offsets from the real time set in minutes, not in seconds).
The clock is updated every time a timer expires. Beforehand, the
timer is primed to expire when the next second starts - ie when the
next multiple of 32 ticks starts (there are 32 ticks to a second on
SIBO computers).
The current tick value can be read from location $41c from the O/S
dataspace, using CALL($078b). In the program, 10 contiguous bytes
are read from this location:
the first two give a value in ticks (read into t%)
the next four (read into j&) are ignored
the final four (read into t&) give the current time in seconds.
Note that the declaration
local t%,j&,t&
is crucial to having these three Opl variables stored contiguously,
so that the one CALL($078b) reads all three at once.
The calculation of how long to wait until the next second starts is
tint&=10-((t% and $1f)*10)/32
where the answer is in 1/10 of a second - because this is how timers
are queued. (The conversion between 1/32 and 1/10 is unfortunate,
but there you have it.)
The effect of
ioa(tcb%,1,tstat%,tint&,#0)
is that a timer completion event should occur after tint& tenths of a
second. The final parameter #0 is just to keep the translator happy
(some ioa calls require a final parameter). The second parameter, 1,
indicates that a RELATIVE timer is required - which will NOT waken
the computer up. The first parameter, tcb%, is the handle of the
timer control block opened with the prior call
ioopen(tcb%,"TIM:",-1)
where the final -1 is again just to keep the translator happy.
The parameter tstat% in the ioa call gets set to -46 when the call is
made, and gets set to some other value (0 in this case in fact) when
the event has occurred.
How the elapsed time is calculated
----------------------------------
The elapsed time is calculated as
e&=o&+t&-s&
where t& is the current time in seconds (see above), s& was the time
in seconds when the program last received a foreground or on message
(see below), and o& is the amount of "old" or previous time carried
forward from the last time the program was in foreground or the
computer was switched on.
The asynchronous version of GETEVENT
------------------------------------
While waiting for the next timer to expire, the program also needs
to be able to respond to normal keypresses, and also to special
messages such as background, foreground, and on.
In general, the program cannot of course predict which type of event
will happen next - timer expiry or keypress. Hence the requirement
for asynchronous i/o:
queue a timer
queue a GETEVENT
call IOWAIT
then find out which type of event has actually occurred - by
testing the values of the "status words" tstat% and cstat%. (The
status word has value -46 while the event remains pending, ie
incomplete).
Were it not for the need to service foreground, background, and on
events, the simple call
keya(cstat%,k%(1))
would have sufficed. However, this does not include these special
sorts of keypresses.
The solution is to call
ioa(-2,14,cstat%,k%(1),#0)
instead:
the handle -2 has the special meaning of the console handle. In
contrast to the timer handle, tcb%, you don't have to do an ioopen,
since the Opl runtime has already opened the console, on your behalf.
The service 14 is actually P_EVENT_READ - see the Console chapter of
the I/O Devices Reference in the SDK for full details. This is the
console service GETEVENT relies upon.
You may be able to guess that the Opl call
GETEVENT(k%(1))
is just shorthand for
iow(-2,14,k%(1),#0)
Other details
-------------
The remainder of the program is just trickery of various sorts.
To start with, a read is queued only to the console.
The first event received will always be a foreground message ($401),
which has the effect of starting the timer off. (The call to
IOSIGNAL just has the effect of ensuring that the next IOWAIT returns
at once.)
On passing into background ($402), the timer is suspended:
iow(tcb%,4,#0,#0)
iowaitstat tstat%
and the timer part of the code won't be entered again until tstat%
becomes different from -46 again. This will be effected in the code
handling foreground or on events.
Note that an on message ($403) is treated in code as being like a
background message ($402) followed by a foreground message ($401).
Other notes
-----------
If you rearrange this code, you may find your program terminates with
an "exit 73". This means the O/S has shot you because you have
requeued a request to an i/o device while the last one was still
outstanding.
The program won't run properly on a SIBO emulation on a PC, since
ticks are different from 1/32 of a second in this case.
If this program called up a dialog or a menu, it would have to switch
the timer off first. This is because you won't receive any special
messages while a dialog or menu is current.
Geteva will of course keep your Series3 turned on indefinitely, since
it neglects to call
call ($138b,0,0,0,0,0) :rem GenMarkNonActive
These notes prepared by DavidW on 24/6/92.