home *** CD-ROM | disk | FTP | other *** search
/ The Datafile PD-CD 3 / PDCD_3.iso / pocketbk / utilsf / geteva / GETEVA.DOC next >
Text File  |  1992-06-24  |  6KB  |  151 lines

  1. Comments on geteva.opl
  2. ======================
  3.  
  4. This program demonstrates:
  5.     * An asynchronous form of GETEVENT
  6.     * How to keep a clock ticking over on the screen, once each
  7. second, that measures only time in foreground (and only time when the
  8. machine is switched on), without burning round in a continuous loop
  9.     * At the same time, the program is ready to respond at once to
  10. any keypresses received
  11.     * How to peek the system time to within 1/32 of a second.
  12.  
  13. The program can also be viewed simply as an example of asynchronous
  14. i/o, iowait, status words, and iosignal.  These techniques allow very
  15. powerful results.  For general background to these techniques, see in
  16. the first instance the chapter "Fundamental Programming Guidelines"
  17. in the "General Programming Manual" of SDK 1.10.  (This is written
  18. for C programmers, but all the same concepts carry over into Opl.)
  19.  
  20. How the clock updates
  21. ---------------------
  22. The clock starts at "0:00" and ticks over once each second. 
  23. Unfortunately, there are no flags for GCLOCK to achieve this (these
  24. system clocks always display an "hours" field, and can only have
  25. their offsets from the real time set in minutes, not in seconds).
  26.  
  27. The clock is updated every time a timer expires.  Beforehand, the
  28. timer is primed to expire when the next second starts - ie when the
  29. next multiple of 32 ticks starts (there are 32 ticks to a second on
  30. SIBO computers).
  31.  
  32. The current tick value can be read from location $41c from the O/S
  33. dataspace, using CALL($078b).  In the program, 10 contiguous bytes
  34. are read from this location:
  35.     the first two give a value in ticks (read into t%)
  36.     the next four (read into j&) are ignored
  37.     the final four (read into t&) give the current time in seconds.
  38. Note that the declaration
  39.     local t%,j&,t&
  40. is crucial to having these three Opl variables stored contiguously,
  41. so that the one CALL($078b) reads all three at once.
  42.  
  43. The calculation of how long to wait until the next second starts is
  44.     tint&=10-((t% and $1f)*10)/32
  45. where the answer is in 1/10 of a second - because this is how timers
  46. are queued.  (The conversion between 1/32 and 1/10 is unfortunate,
  47. but there you have it.)
  48.  
  49. The effect of
  50.     ioa(tcb%,1,tstat%,tint&,#0)
  51. is that a timer completion event should occur after tint& tenths of a
  52. second.  The final parameter #0 is just to keep the translator happy
  53. (some ioa calls require a final parameter).  The second parameter, 1,
  54. indicates that a RELATIVE timer is required - which will NOT waken
  55. the computer up.  The first parameter, tcb%, is the handle of the
  56. timer control block opened with the prior call
  57.     ioopen(tcb%,"TIM:",-1)
  58. where the final -1 is again just to keep the translator happy.
  59.  
  60. The parameter tstat% in the ioa call gets set to -46 when the call is
  61. made, and gets set to some other value (0 in this case in fact) when
  62. the event has occurred.
  63.  
  64. How the elapsed time is calculated
  65. ----------------------------------
  66. The elapsed time is calculated as
  67.     e&=o&+t&-s&
  68. where t& is the current time in seconds (see above), s& was the time
  69. in seconds when the program last received a foreground or on message
  70. (see below), and o& is the amount of "old" or previous time carried
  71. forward from the last time the program was in foreground or the
  72. computer was switched on.
  73.  
  74. The asynchronous version of GETEVENT
  75. ------------------------------------
  76. While waiting for the next timer to expire, the program also needs
  77. to be able to respond to normal keypresses, and also to special
  78. messages such as background, foreground, and on.
  79.  
  80. In general, the program cannot of course predict which type of event
  81. will happen next - timer expiry or keypress.  Hence the requirement
  82. for asynchronous i/o:
  83.     queue a timer
  84.     queue a GETEVENT
  85.     call IOWAIT
  86.     then find out which type of event has actually occurred - by
  87. testing the values of the "status words" tstat% and cstat%.  (The
  88. status word has value -46 while the event remains pending, ie
  89. incomplete).
  90.  
  91. Were it not for the need to service foreground, background, and on
  92. events, the simple call
  93.     keya(cstat%,k%(1))
  94. would have sufficed.  However, this does not include these special
  95. sorts of keypresses.
  96.  
  97. The solution is to call
  98.     ioa(-2,14,cstat%,k%(1),#0)
  99. instead:
  100.     the handle -2 has the special meaning of the console handle.  In
  101. contrast to the timer handle, tcb%, you don't have to do an ioopen,
  102. since the Opl runtime has already opened the console, on your behalf.
  103.  
  104. The service 14 is actually P_EVENT_READ - see the Console chapter of
  105. the I/O Devices Reference in the SDK for full details.  This is the
  106. console service GETEVENT relies upon.
  107.  
  108. You may be able to guess that the Opl call
  109.     GETEVENT(k%(1))
  110. is just shorthand for
  111.     iow(-2,14,k%(1),#0)
  112.  
  113. Other details
  114. -------------
  115. The remainder of the program is just trickery of various sorts.
  116. To start with, a read is queued only to the console.
  117. The first event received will always be a foreground message ($401),
  118. which has the effect of starting the timer off.  (The call to
  119. IOSIGNAL just has the effect of ensuring that the next IOWAIT returns
  120. at once.)
  121.  
  122. On passing into background ($402), the timer is suspended:
  123.     iow(tcb%,4,#0,#0)
  124.     iowaitstat tstat%
  125. and the timer part of the code won't be entered again until tstat%
  126. becomes different from -46 again.  This will be effected in the code
  127. handling foreground or on events.
  128.  
  129. Note that an on message ($403) is treated in code as being like a
  130. background message ($402) followed by a foreground message ($401).
  131.  
  132. Other notes
  133. -----------
  134. If you rearrange this code, you may find your program terminates with
  135. an "exit 73".  This means the O/S has shot you because you have
  136. requeued a request to an i/o device while the last one was still
  137. outstanding.
  138.  
  139. The program won't run properly on a SIBO emulation on a PC, since
  140. ticks are different from 1/32 of a second in this case.
  141.  
  142. If this program called up a dialog or a menu, it would have to switch
  143. the timer off first.  This is because you won't receive any special
  144. messages while a dialog or menu is current.
  145.  
  146. Geteva will of course keep your Series3 turned on indefinitely, since
  147. it neglects to call
  148.     call ($138b,0,0,0,0,0) :rem GenMarkNonActive
  149.  
  150. These notes prepared by DavidW on 24/6/92.
  151.