home *** CD-ROM | disk | FTP | other *** search
- 2 TIMER DEVICE
-
- 2.1 INTRODUCTION
-
- The timer device may not sound very exciting but it can be
- extremely useful. Many so called "high level" devices are using
- the timer device, and very often you need to use it yourself.
- It is not very accurate since other tasks running at the same
- time may delay the time reports, but is usually good enough,
- and in the long run it is very accurate.
-
- The timer device is a very simple device. It's main task is to
- send messages to all its users after specified time periods.
- The timer device can also compare different time periods, and
- add as well as subtract one time period with another. No
- thrills, but useful stuff.
-
-
-
- 2.2 TIMER
-
- The timer device's main task is to send time reports to all its
- users. It is controlled like all other devices by sending
- request blocks, and is therefore easy to handle. See previous
- chapter "Devices" for more information about devices and
- request blocks.
-
-
-
- 2.2.1 TIME REQUEST
-
- The timer device's request block is an "extended" request
- block and is defined in header file "devices/timer.h":
-
- struct timerequest
- {
- struct IORequest tr_node;
- struct timeval tr_time;
- };
-
- tr_node: As with all request blocks, the top part consists of
- an IORequest structure which is used by Exec to handle
- the requests. While using the timer device you do not
- need to use this structure (well, at least not very
- often). Simply let the system take care of it.
-
- tr_time: The second part of the request block consists of a
- timeval structure: (Also defined in the header file
- "devices/timer.h".)
-
- struct timeval
- {
- ULONG tv_secs;
- ULONG tv_micro;
- };
-
- tv_secs: The number of seconds you want to wait before
- the time request should be completed.
-
- tv_micro: The number of microseconds. Note that the
- timer device is not very accurate. Your
- requests can be delayed by other programs
- running at the same time, but in the long
- run the timer device is accurate enough.
-
-
- As with all devices you have to connect a message port to
- the request block with which the timer device can talk to you.
- Create a message (reply) port by calling the CreatePort()
- function. Normally you should not use any name (the message
- port should not be made public) and priority set to 0 (normal
- priority).
-
- Synopsis: msg_port = CreatePort( name, pri );
-
- msg_port: (struct MsgPort *) Pointer to the new MsgPort
- structure, or NULL if something went wrong.
-
- name: (char *) Pointer to a string containing the name
- of the message port, or NULL. When working with
- devices you normally do not need to use any name.
-
- pri: (BYTE) This message port's priority. Usually set
- to 0 (normal priority).
-
-
- Once you have successfully opened a message port you may
- allocate and initialize the request block. Since the request
- block is "extended" (not the same size as the "standard" -
- IOStdReq structures) you need to use the CreateExtIO()
- function to allocate and initialize the request block.
- (Do not use the CreateStdIO() function!)
-
- Synopsis: ext_req = CreateExtIO( msg_port, size );
-
- ext_req: (struct IORequest *) Pointer to the new extended
- request block, or NULL if the request block could
- not be created.
-
- msg_port: (struct MsgPort *) Pointer to the message port
- the CreatePort() function returned. The timer
- device will use it to send messages to you.
-
- size: (long) The number of bytes that should be allocated
- for the extended request block. Use the function
- sizeof() to find the exact number of bytes needed.
- Example: sizeof( struct timerequest ).
-
-
- Here is an example:
-
- /* The reply port: */
- struct MsgPort *replymp;
-
- /* The timer request block: */
- struct timerequest *timer_req;
-
- ...
-
-
- /* Get a reply port: (No name, normal priority) */
- replymp = (struct MsgPort *)
- CreatePort( NULL, 0 );
- if( !replymp )
- clean_up( "Could not create the reply port!" );
-
- /* Allocate and preinitialize a request block: */
- timer_req = (struct timerequest *)
- CreateExtIO( replymp, sizeof(struct timerequest) );
- if( !timer_req )
- clean_up( "Could not create the request block!" );
-
-
-
-
- 2.2.2 OPEN THE TIMER DEVICE
-
- Once you have successfully created a request block you can
- "open" the timer device. You should, however, first decide how
- accurate you want the timer device to be. The timer device can
- work in two different modes:
-
- 1. The timer device can use the video beam to control its own
- timer. This will make the timer very stable over long time
- periods, but is not very accurate for short intervals
- (less than one second).
-
- This mode is easy for the timer device to handle and thus
- little computer time is used. This mode is called
- "vertical blank timer" and the flag is "UNIT_VBLANK".
-
- 2. If you want to use very short time periods (less than one
- second) it can sometimes be necessary to use the special
- CIA chips for the timer. The CIA chips has a much higher
- "resolution" than the video beam, thus it will result in
- very accurate time periods for short intervals. This mode
- is more complicated than the vertical blank timer, and
- more computer time is therefore used. This mode is called
- "micro hertz timer" and the flag is "UNIT_MICROHZ"
-
-
- The general rule is that time periods longer than one second
- should use the vertical blank timer. Else, if really high
- "resolution" is needed, the micro hertz timer should be used.
-
- Once you have decided which mode should be used you can open
- the timer device. No frills here, simply use the OpenDevice()
- function.
-
- Synopsis: error = OpenDevice( name, unit, req, flags );
-
- error: (long) If OpenDevice() managed to open the timer
- device it returns 0, else an error number is
- returned.
-
- name: (char *) Name of the device you want to open.
- The name for the timer device has been defined
- as "TIMERNAME" (header file "devices/timer.h").
-
- unit: (long) Which timer mode you want the device to
- use. Set this field to either "UNIT_VBLANK" or
- "MICROHZ".
-
- req: (struct IORequest *) Pointer to a previously
- initialized request block.
-
- flags: (long) Special flags which are ignored by the timer
- device.
-
-
- Here is an example:
-
- /* Open the Timer Device: ("vertical blank timer") */
- error = OpenDevice( TIMERNAME, UNIT_VBLANK, timer_req ,0 );
- if( error )
- clean_up( "Could not open the Timer Device!" );
-
-
-
- 2.2.3 SET TIME REQUEST
-
- When the timer device has been opened you can start to send your
- time requests. You specify the number of seconds and microseconds
- that should pass before a message will be sent by initializing
- the timeval structure. Note that the time you set is the minimum
- time. When the exact time has elapsed it may happen that some
- other program is for the moment occupying the processor, and
- thus the time message will be delayed for some microseconds.
-
- You must also tell the device that you are sending a time
- request. You do it by setting the flag "TR_ADDREQUEST" in the
- "io_Command" field.
-
- The request can now be sent to the device. Either use the DoIO()
- function if you want to wait for the request to be completed,
- or use the SendIO() function if you want your program to
- continue to run while the request is executed. See the previous
- chapter for a complete explanation on when and how the DoIO()
- and SendIO() functions should be used.
-
- Here is an example:
-
- /* Set time: (5.25 seconds)*/
- timer_req->tr_time.tv_secs = 5;
- timer_req->tr_time.tv_micro = 250000;
-
- /* We want to add a time request: */
- timer_req->tr_node.io_Command = TR_ADDREQUEST;
-
- /* Do our request and return when done: */
- /* (Our task is put to sleep for 5.25 sec.) */
- DoIO( timer_req );
-
-
- If you want to send multiple requests you have to use several
- request blocks which each has been properly initialized. You
- must then also use the function SendIO() and not DoIO() since
- your program will else be put to sleep directly after the first
- request has been sent. See example 2.
-
- Each time you send a request to the timer device all values in
- the timeval structure are destroyed. You must therefore always
- reinitialize these fields before you may repost the request to
- device.
-
-
-
- 2.2.4 CLEAN UP
-
- As always you must remember to clean up after you. All
- allocated request blocks must be removed, all opened message
- ports closed as well as all devices.
-
- Fist you should close the timer device. Note that all requests
- you have posted to that device must either have been completed
- or aborted before you may close the device! All devices are
- closed by the special CloseDevice() function.
-
- Synopsis: CloseDevice( req );
-
- reg: (struct IORequest *) Pointer to the timer device's
- own request block. (The same request block which
- was used when you opened the timer device.)
-
-
- The request blocks are deleted by calling the DeleteExtIO()
- function. Note that the request must have been completed or
- aborted before you may delete it! Note also that you can not
- use the DeleteStdIO() function since the timer device is using
- extended request blocks.
-
- Synopsis: DeleteExtIO( std_req, size );
-
- std_req: (struct IOStdReq *) Pointer to the request block
- you want to delete.
-
- size: (long) The size of the request block, in bytes.
- Use the function sizeof() to get the correct number
- of bytes. Example: sizeof( struct timerequest ).
-
-
- Finally you should close all message ports by calling the
- DeletePort() function. All messages must have been removed
- before you may close the message port.
-
- Synopsis: DeletePort( msg_port );
-
- msg_port: (struct MsgPort *) Pointer to the MsgPort structure
- that should be deleted.
-
-
- Here is a short example:
-
- /* Close the Timer Device: */
- CloseDevice( timer_req );
-
- /* Delete the request block: */
- DeleteExtIO( timer_req, sizeof( struct timerequest) );
-
- /* Remove the message port: */
- DeletePort( replymp );
-
-
-
- 2.2.5 EXAMPLE
-
- Here is a complete example on how to use the timer device. It
- will open a message port, create a request block, open the timer
- device, and finally put itself to sleep for 10 seconds. When the
- time has elapsed everything is returned and the program
- terminates. (Hmmm, very similar to example 1.)
-
- #include <exec/types.h> /* STRPTR */
- #include <exec/ports.h> /* struct Message */
- #include <exec/memory.h> /* MEMF_PUBLIC */
- #include <devices/timer.h> /* TIMERNAME */
-
- /* The reply port: */
- struct MsgPort *replymp;
-
- /* The timer request block: */
- struct timerequest *timer_req;
-
- /* When the Timer Device is open this variable is TRUE: */
- BOOL not_opened = TRUE;
-
- /* Declare our functions: */
- void clean_up();
- void main();
-
- void main()
- {
- /* 1. Get a reply port: */
- replymp = (struct MsgPort *)
- CreatePort( NULL, 0 );
- if( !replymp )
- clean_up( "Could not create the reply port!" );
-
- /* 2. Get an extended request block: */
- timer_req = (struct timerequest *)
- CreateExtIO( replymp, sizeof( struct timerequest) );
- if( !timer_req )
- clean_up( "Could not create the IO!" );
-
- /* 3. Open the Timer Device: */
- not_opened = OpenDevice( TIMERNAME, UNIT_VBLANK, timer_req ,0 );
- if( not_opened )
- clean_up( "Could not open the Timer Device!" );
-
- /* 4. Set our request: */
- timer_req->tr_node.io_Command = TR_ADDREQUEST; /* Add a request. */
- timer_req->tr_time.tv_secs = 10; /* 10 seconds. */
- timer_req->tr_time.tv_micro = 0; /* 0 micro seconds. */
-
- /* 5. Do our request: (Wait 10 seconds) */
- printf( "Good night...\n" );
- DoIO( timer_req );
- printf( "Good morning!\n" );
-
- /* Clean up and quit: */
- clean_up( "The End!" );
- }
-
- void clean_up( text )
- STRPTR text;
- {
- /* Close the Timer Device: */
- if( !not_opened )
- CloseDevice( timer_req );
-
- /* Delete the extended request block: */
- if( timer_req )
- DeleteExtIO( timer_req, sizeof( struct timerequest) );
-
- /* Remove the message port: */
- if( replymp )
- DeletePort( replymp);
-
- /* Print the last message: */
- printf( "%s\n", text );
-
- /* Quit: */
- exit( 0 );
- }
-
-
-
- 2.3 SYSTEM TIME
-
- The timer device can also be used to get the current system
- time. It should be noted that this system time has nothing to
- do with the Amiga's internal clock. The system time is simply
- a value which is initialized to the date when the boot disk was
- last modified. The value is relative to 1 January 1978,
- time 00:00:00.
-
- Although it may not be a "correct" time value it can be useful.
- For example, if you want to adjust several time periods with
- each other it can be handy to have an external timer like the
- system time.
-
- With help of the timer device you can both get the current
- system time as well as set it to a new value.
-
-
-
- 2.3.1 GET SYSTEM TIME
-
- To get the current system time you set the flag "TR_GETSYSTIME"
- in the io_Command field of the request block and send the
- request block to the timer device. When the timer device has
- completed the request it is returned and you may now examine the
- timeval structure where the current system time has been stored.
-
- Each time you get the system time you will receive a value which
- is different from previous calls (it is an unique value).
-
- Here is a short example:
-
- /* Get the current system time: */
- timer_req->tr_node.io_Command = TR_GETSYSTIME;
-
- /* Do the request: */
- DoIO( timer_req );
-
- /* Print the current system time: */
- printf( "The current system time is:\n" );
- printf( "Seconds: %d\n", timer_req->tr_time.tv_secs );
- printf( "Microseconds: %d\n", timer_req->tr_time.tv_micro );
-
-
-
- 2.3.2 SET SYSTEM TIME
-
- To set the system time to a new value simply set the
- "TR_SETSYSTIME" flag in the io_Command field of the request
- block, set the new time in the timeval structure, and finally
- send the request block to the timer device.
-
- You may only set values that are greater than the current
- time. The timer device or other programs may be confused if
- the time suddenly went backwards.
-
- Here is a short example:
-
- /* Add two hours and 0.4 seconds: */
- tr->tr_time.tv_secs += 60 * 60 * 2;
- tr->tr_time.tv_micro += 400000;
-
- /* Set the new system time: */
- tr->tr_node.io_Command = TR_SETSYSTIME;
-
- /* Do the request: */
- DoIO( tr );
-
-
-
- 2.4 SPECIAL TIME FUNCTIONS
-
- The timer device can also be used to compare different time
- reports and to add or subtract time values. To do these things
- the timer device contain three functions - CmpTime(), AddTime()
- and Subime(). Since these features are accessed as functions
- rather than using request blocks you have to prepare the timer
- device a little before you may use these functions.
-
- The timer device is using a global pointer which is always
- called "TimerBase". This global pointer is used to find the
- starting address of the three special timer functions. Before
- you may use these functions you must therefore declare and
- initialize the TimerBase pointer. To initialize it simply use
- any request block which is connected to the timer device. In
- the "io_Device" field of the request block you will find the
- current address value of the timer device.
-
- Here is a short example:
-
- /* Declare the global timer pointer: */
- struct Device *TimerBase;
-
- /* ... create request blocks, open timer device etc ... */
-
- /* Get the global pointer to the timer device: */
- TimerBase = timer_req->tr_node.io_Device;
-
-
- Once you have found the TimerBase pointer you may start to use
- the timer functions. Their primary usage is to coordinate
- different time requests with each other.
-
-
-
- 2.4.1 COMPARE TIMES
-
- The CmpTime() function is used to compare two timeval
- structures and returns 0 if they were identical, -1 if the
- first timeval structure was greater than the second, and
- 1 if the opposite (the second timeval structure was greater
- than the first).
-
- Synopsis: dif = CmpTime( time1, time2 );
-
- dif: (long) If the two time values were identical 0 is
- returned. If the first time value was greater than
- the second time value -1 is returned, and if the
- opposite (the second time value is greater than the
- first time value) 1 is returned.
-
- time1: (struct timeval *) Pointer to the first timeval
- structure.
-
- time1: (struct timeval *) Pointer to the second timeval
- structure.
-
-
-
- 2.4.2 ADD TIME
-
- The AddTime() function is used to add the time in one timeval
- structure with the time in another timeval structure.
-
- Synopsis: AddTime( tiem1, time2 );
-
- time1: (struct timeval *) Pointer to the first timeval
- structure. The value of the second timeval
- structure will be added with this timeval
- structure, and the result stored here.
-
- time1: (struct timeval *) Pointer to the second timeval
- structure.
-
-
-
- 2.4.3 SUBTRACT TIME
-
- The SubTime() function is used to subtract the time in one timeval
- structure with the time in another timeval structure.
-
- Synopsos: SubTime( tiem1, time2 );
-
- time1: (struct timeval *) Pointer to the first timeval
- structure. The value of the second timeval
- structure will be subtracted with this timeval
- structure, and the result stored here.
-
- time1: (struct timeval *) Pointer to the second timeval
- structure.
-
-
-
- 2.4.5 EXAMPLE
-
- This short example demonstrates how to use the timer device's
- own functions. ("tr1", "tr2" and "tr3" are three already
- initialized requst blocks.)
-
- /* Set the times: */
- /* Request 1: */
- tr1->tr_time.tv_secs = 10;
- tr1->tr_time.tv_micro = 0;
- /* Request 2: */
- tr2->tr_time.tv_secs = 7;
- tr2->tr_time.tv_micro = 0;
- /* Request 3: */
- tr3->tr_time.tv_secs = 5;
- tr3->tr_time.tv_micro = 0;
-
- /* Get a pointer to the timer device: */
- TimerBase = tr1->tr_node.io_Device;
-
- /* Compare the first two time val structures: */
- printf( "Compare time1 - time2: %d\n",
- CmpTime( &(tr1->tr_time), &(tr2->tr_time) ) );
-
- /* Add the time in the third timeval structure to */
- /* the second timeval structure. The second timeval */
- /* structure should now contain the time 12 sec. */
- AddTime( &(tr2->tr_time), &(tr3->tr_time) );
-
- /* Subtract the time in the third timeval structure with */
- /* the second timeval structure. The second timeval */
- /* structure should now again contain the time 7 seconds. */
- SubTime( &(tr2->tr_time), &(tr3->tr_time) );
-
-
- Note that we have to use pointers to the timeval structures
- as arguments [&(tr1->tr_time]. The parentheses around the
- expression are actually unnecessary since the "->" operator
- already has higher priority than the "&" operator. However,
- this makes it easier to read.
-
-
-
- 2.5 FUNCTIONS
-
- The functions DoIO(), SendIO(), WaitIO(), AbortIO() etc...
- have already been defined in the previous chapter, and I
- will therefore not repeat all this information here.
-
- There exist three functions which are supported by the timer
- device. Before you may use them you have to initialize a
- global pointer named "TimerBase". (See above for more
- information.)
-
-
- CmpTime()
-
- The CmpTime() function is used to compare two timeval
- structures and returns 0 if they were identical, -1 if the
- first timeval structure was greater than the second, and
- 1 if the opposite (the second timeval structure was greater
- than the first).
-
- Synopsis: dif = CmpTime( time1, time2 );
-
- dif: (long) If the two time values were identical 0 is
- returned. If the first time value was greater than
- the second time value -1 is returned, and if the
- opposite (the second time value is greater than the
- first time value) 1 is returned.
-
- time1: (struct timeval *) Pointer to the first timeval
- structure.
-
- time1: (struct timeval *) Pointer to the second timeval
- structure.
-
-
- AddTime()
-
- The AddTime() function is used to add the time in one timeval
- structure with the time in another timeval structure.
-
- Synopsis: AddTime( tiem1, time2 );
-
- time1: (struct timeval *) Pointer to the first timeval
- structure. The value of the second timeval
- structure will be added with this timeval
- structure, and the result stored here.
-
- time1: (struct timeval *) Pointer to the second timeval
- structure.
-
-
- SubTime()
-
- The SubTime() function is used to subtract the time in one
- timeval structure with the time in another timeval structure.
-
- Synopsos: SubTime( tiem1, time2 );
-
- time1: (struct timeval *) Pointer to the first timeval
- structure. The value of the second timeval
- structure will be subtracted with this timeval
- structure, and the result stored here.
-
- time1: (struct timeval *) Pointer to the second timeval
- structure.
-
-
-
- 2.6 EXAMPLES
-
- Example 1
- This example demonstrates how you can use the Timer Device.
- The program will be put to sleep for 10 seconds.
-
- Example 2
- This example demonstrates how you can send several requests
- to the Timer Device.
-
- Example 3
- This example demonstrates how you can use the Timer Device
- to get the current system time. We will then add two hours
- and set the new system time.
-
- Example 4
- This example demonstrates how you can compare, add and
- subtract time values with help of the timer device's own
- functions.
-
-
-