Notes on BEEPOFF.OPL ==================== This Opl program makes a short sequence of beeps just before the S3 switches off (in most cases). It could certainly be improved, eg to play a customisable .WVE sound instead. As it stands, BEEPOFF.OPL works on either the S3a or the S3 classic. The program, and its accompanying notes, may also be of interest as: * an example of multiple event source handling (asynchronous i/o) * how to tell, in your program, whether the processor is busy * how to tell if mains is plugged in, etc, etc. Background: switching off and capturing the "off event" ------------------------------------------------------- There are four reasons why an S3(a) can switch off: 1 A program calls OFF explicitly 2 The user switches OFF 3 Auto-switchoff 4 Low power emergency switch off. BEEPOFF only catches cases 2 and 3. It catches case 2 by "capturing" the off key press, which has the special value $2003. It catches case 3 by monitoring a location ($40c) in operating system dataspace, which states how many seconds there are to go before auto-switchoff, and *pre-empting* auto-switchoff by a couple of seconds. Thus there is no question of BEEPOFF actually intercepting any "off event" (such as device drivers can do): this is, frankly, far too dangerous a thing to do, and is also far beyond the scope of this discussion (it also turns out that, for most purposes, what is done in BEEPOFF is perfectly sufficient to meet the requirements). Monitoring auto-switchoff ------------------------- The routine TIMELFT%: contains the core logic here. First it calls NOTIFM%: (NOT IF no auto-switchoff if on Mains), since if this condition applies (discussed below), there will no be auto-switchoff. Next, it uses GenGetOsData to read four bytes from $40a in O/S dataspace: $40a is the "auto-switchoff value", in seconds (-1 if disabled) $40c is how many seconds are left before auto-switchoff. Preventing BEEPOFF's activity from counting ------------------------------------------- Note that for this approach to have any relevance, BEEPOFF must itself avoid counting as "activity that resets the auto-switchoff counter". This is achieved by calling GenMarkNonActive in startup code. Handling the "If no external power" setting (S3a only) ------------------------------------------------------ This is the role of NOTIFM%:. The main call here is GenGetAutoMains, which returns 1 if this applies. In this case, NOTIFM%: must go on to call MAINSIN%: to see whether mains are present. Note that GenGetAutoMains is *not supported* on the S3 classic. If you call it on that, your program will panic. Hence the test on the Window Server type number at the start of NOTIFM%:. Capturing the OFF key: ---------------------- The line of code call($c58d,$2003,$e08) does this. The BX parameter is clearly the keycode value. The CL parameter (8) is the *required* modifier value (ie Psion modifier down). The CH parameter ($e) also contains the Shift and Control modifiers. The result of this call is that (eg) Shift-Off or Control-Off are *not* captured. Thus (eg) Control-Off will switch the S3 off without code in BEEPOFF getting to hear about it. Which is probably useful. Handling multiple events ------------------------ BEEPOFF must watch out for either of two things: * the off key being delivered * the auto-switchoff counter going under two seconds. One approach here would be continuous polling, but that would be strongly contrary to the power-saving philosophy of Epoc. Instead, I use a (relative) timer to waken the program up when a suitable duration has elapsed, and an asynchronous keyboard request (KEYA) to waken the program up when a key has been delivered. At any one time, the program always has a keyboard read outstanding, and also a relative timer outstanding. It then calls IOWAIT to wait for either of these events "completing". When it comes out of the IOWAIT, it then tests the two associated "status words" to see which event has actually occurred. "Stray signal" panic -------------------- If you wish to rearrange this code, you'ld probably best keep this check in, to alert you as quickly as possible to bugs you may introduce in the central "get-event" logic. The call to GenTickle --------------------- The routine DOBEEP: starts by calling GenTickle, to *explicitly* reset the inactivity counter - to prevent the S3 switching off partway through the subsequent sound sequence (not that it would, given the code as it stands, but if you change it, you may be grateful for this call). These notes prepared by: ------------------------ David Wood, 18th October 1993.