
file :  /kb/timer.doc.text
date :  08-Feb-1983   kb

This document describes the system interface of the TIMER driver.

The Timer driver performs 3 services. First, it maintains a table
of user timer service routines.  It invokes the user routines
during a 50 millisecond timer interrupt.  Second, it uses the VIA
timer number 2 to produce a Bell sound (e.g. control G).  Last,
the driver will read and write the time and date clock.

The first service, 50 milliseconds timer call, is setup by the
Timer unitstatus routine.  The serviced routines are invoked
during the VIA timer #1 interrupt service procedure.  This
service call is not a precise 50 ms. interval call.  Users who
have very time critical processes must setup VIA timer #2 and
monitor its activity.  Timer #1 is for the exclusive use of the
Timer driver.  Therefore, do not use it for user controlled
timing activities.

The Timer driver unitstatus performs 4 table manipulation actions
depending on the value of the input parameters.  OS defined
parameters for the unitstatus procedure are : unit number (word),
buffer address (long word), and control (word) .  The Timer
driver's 4 actions are Create, Enable, Disable and Delete table
entry.  The Timer driver selects the correct action by the value
passed as the control parameter. The control parameter values are
1 for Create, 2 for Delete, 3 for Disable and 4 for Enable. The
remaining parameters to the procedure are passed in a parameter
block, whose address is passed as the unitstatus parameter buffer
address. Space in the parameter block must be made for Output
values as well as Input values.

The following is a description of the parameters in each of the
table manipulation procedure's parameter blocks.

Create table entry function takes as input an address of the user
service routine (long word), the count of 50 ms. periods before
interrupt service routine call (word) and a word of Flags and
returns a table entry ID (word) of the entry made.  The count
ranges from 1 to 65,535, where a 1 value means make a call to the
user service routine on every 50 millisecond interval timer
interrupt.  Currently, 2 bit flags are defined in the word of
Flags.  The first is the Continuous/One-shot flag.  When it is
clear the table entry is used until it is removed by a Delete
call.  When the flag is set the entry is used in a one-shot mode.
Therefore, after the user service routine is called and it
returns the associated table entry is automatically Deleted.  The
second flag is the Skip First Call flag.  This flag tells the
Timer driver to ignore the first call to be made to the
corresponding user service routine when the down counter reaches
0 (zero). Since the Create operation is performed asynchronously
to the interrupts generated by the free running interval timer
(VIA timer #2), it is likely that the first user service routine
call for this entry with this flag clear will occur in less time
than the requested interval specified by the Count.  Therefore,
the user should use this flag when a minimum delay time of the
count of interrupt periods is needed.  The Create function has 3
input parameters and 1 output parameter for a total of 10 bytes,
all of which must start on a even word boundary.

Create Parameter block in Pascal fragment :

CONST
        OneShot   = 2;
        SkipFirst = 4;

TYPE    record
                UserServiceRtn : pointer; {Input parameter}
                Count          : integer; {Input parameter}
                Flags          : integer; {Input parameter}
                TableID        : integer; {Output parameter}
                end;{record}

Delete table entry procedure takes the table entry ID (word) for
the entry desired and deletes that entry from the table.  This
table entry ID is the same value returned by the Create function.
The Delete procedure has 1 input parameter and no (zero) output
parameters, for a total of 2 bytes.

The Disable procedure allows the user to prevent the Timer
interrupt routine from calling the user's timer service routine
without Deleting the user's table entry.  The procedure has one
input parameter, the table entry ID of the entry to disable. It
has no output parameters.  The total number of bytes for this
procedure's parameter block is 2.

The Enable procedure allows the user to restart a table entry. It
clears the Disable condition and resets the down counter to it's
starting condition. It can be used for either starting up a
Disabled table entry or restarting a running entry before it
causes a call to the service routine.  This procedure has only 1
parameter, the table entry ID, for a total of 2 bytes.

All the actions will place error condition codes within the
IORESULT system variable.  Only two error codnditions are
defined.  They are a) table full and b) no such entry (or invalid
table entry ID).

User timer service routines are called during the interrupt
processing.  They should take a minimal amount of time; I suggest
less than 500 microseconds.  Therefore, don't use them for doing
any significant processing.  They would be best used for setting
flags informing the program that a timeout event has occurred.

The table operations are not indivisible.  Therefore, a user
timer service routine may be called while the user is making a
Delete or Disable call.  Consequently, any operation done by the
user service routine must be easily reversable after the table
operation call.  This only reinforces the need for keeping the
user service routines simple with few destructive operations.

All user timer service routines must return to the Timer driver
interrupt routine via the RTS instruction.  Also, no argument
passing is available to the the user's timer service routine.

For Pascal programs which want to have a user timer interrupt
service routine there are a few restrictions.  First, the
procedure, NOT a function, to be used as the service routine must
be a global procedure.  Functions cannot be used as user timer
service routines.  The procedure must return to the Timer driver
and cannot use Global GOTO's.  When the table entry is created,
the routine that calls the Timer driver Create function must be a
resident part of the program which contains the user's service
routine procedure.

The second service, the Bell, is also performed by the Timer
unitstatus function.  The unitstatus parameters must be set as
follows :  Control must be set to 0 and buffer address must point
to the Bell parameter block.  The parameter block contains 3
parameters, Bell frequency (word), pattern of 8 on and offs of
the speaker (byte), a filler byte to keep block to even number of
bytes, and the duration in counts of Timer #1 interrupt periods
(50 milliseconds), a word.  The Bell parameter block is 6 bytes.
The pattern of 8 on and offs of the speaker is a byte with a bit
equal to 1 for speaker on and 0 for speaker off. The Timer driver
uses VIA timer #2 non-exclusively.

The third service, the time and date clock, is accessed via the
Unitread and Unitwrite driver interfaces.  The clock interfaces
require a Clock Parameter Block.  This is a fixed length, fixed
format interface.  Unlike other drivers, the timer driver cannot
do reads and writes of variable length data strings.  The Clock
Parameter Block is one field longer for the Unitwrite procedure
then for the Unitread procedure.  The following is a Pascal
fragment which describes the Clock Parameter Block.

               type
                  clockPB = record
                              DayofWeek : 1..7;
                              Month : 1..12;
                              Day : 1..31;
                              Hour : 0..23;
                              Mins : 0..59;
                              Secs : 0..59;
                              Tenths : 0..9;
                              case INTEGER of
                                0 : ( {Write only} LeapYear : 0..3);
                               end;{variant}
                             end;{record}

Though each field is a sub range of the integer type and could
fit in less space then a word each field MUST be a word long.
Therefore, declare each field as an integer, but restrict your
useage to the valid range.  The driver does validate the range in
case of a user error. Unfortunately, the Day parameter is not
completely verified.  If the month specified is Febraury (Month
:= 2), but the Day is 30, the driver does not report an error.

Except for the fields DayofWeek, Tenths, and LeapYear the field
meanings are self-explanatory.  DayofWeek specifies which day it
is, such as Monday, Tuesday, etc.  The value 1 specifies Sunday
while 7 specifies Saturday.  The field Tenths is tenths of a
second.  Finally, the clock has no register set for years.
However, to keep the correct date after a year change the clock
tracks if this year is a leap year.  The LeapYear field specifies
the number of years AFTER the last leap year.  Therefore, if this
year is leap year then the field should be assigned to 0 (zero).
Consequently, if last year was leap year then the field should be
assigned to 1 (one), and so forth.  The LeapYear field is only
used when setting the clock (Unitwrite). It is not returned when
reading the clock (Unitread).

To set the clock, first fill in all the fields in the Clock
Parameter Block, including the LeapYear field.  Next, call the
timer driver Unitwrite to set the clock.

                Unitwrite( TimerDriverNumber, WriteParmBlock,
                LengthWriteParmBlock );

The driver will set the IORESULT variable if the parameter block
is in error.

To read the clock just call the timer driver Unitread with the
Clock Parameter Block.

                Unitread( TimerDriverNumber, ReadParmBlock,
                LengthReadParmBlock );

The correct length of the Read version of the Clock Paramter
Block must be passed to the driver.  If it is to short, an error
is returned in IORESULT and the clock is NOT read.

The Timer driver unitinstall procedure sets-up the VIA,
initializes the timer table to no entries value, starts the 50
ms. interrupt driven interval timer (VIA timer #1), and
initializes the clock chip.  Clock initialization makes sure the
clock is running, the chip is not in test mode, and the interrupt
capabilities of the chip are reset.  The chip can interrupt,
however, it is not connected to the system interrupt system and
it's interrupt is ignored.  The interrupt is cleared and reset so
it does not effect the running of the clock.

The Timer driver unitunmount procedure turns off the VIA timer
interrupt for Timer #2.  It also installs in the timer interrupt
vector a pointer to a ReTurn from Exception (RTE) instruction to
insure system integrity in case of a spurrious level 5 interrupt.
