home *** CD-ROM | disk | FTP | other *** search
/ World of A1200 / World_Of_A1200.iso / datafiles / text / c_manual / devices / timerdevice / timerdevice.doc < prev    next >
Text File  |  1995-02-27  |  22KB  |  683 lines

  1. 2    TIMER DEVICE
  2.  
  3. 2.1  INTRODUCTION
  4.  
  5. The timer device may not sound very exciting but it can be
  6. extremely useful. Many so called "high level" devices are using
  7. the timer device, and very often you need to use it yourself.
  8. It is not very accurate since other tasks running at the same
  9. time may delay the time reports, but is usually good enough,
  10. and in the long run it is very accurate.
  11.  
  12. The timer device is a very simple device. It's main task is to
  13. send messages to all its users after specified time periods.
  14. The timer device can also compare different time periods, and
  15. add as well as subtract one time period with another. No
  16. thrills, but useful stuff.
  17.  
  18.  
  19.  
  20. 2.2  TIMER
  21.  
  22. The timer device's main task is to send time reports to all its
  23. users. It is controlled like all other devices by sending
  24. request blocks, and is therefore easy to handle. See previous
  25. chapter "Devices" for more information about devices and
  26. request blocks.
  27.  
  28.  
  29.  
  30. 2.2.1  TIME REQUEST
  31.  
  32. The timer device's request block is an "extended" request
  33. block and is defined in header file "devices/timer.h":
  34.  
  35. struct timerequest
  36. {
  37.   struct IORequest tr_node;
  38.   struct timeval   tr_time;
  39. };
  40.  
  41. tr_node: As with all request blocks, the top part consists of
  42.          an IORequest structure which is used by Exec to handle
  43.          the requests. While using the timer device you do not
  44.          need to use this structure (well, at least not very
  45.          often). Simply let the system take care of it.
  46.  
  47. tr_time: The second part of the request block consists of a
  48.          timeval structure: (Also defined in the header file
  49.          "devices/timer.h".)
  50.  
  51.          struct timeval
  52.          {
  53.            ULONG tv_secs;
  54.            ULONG tv_micro;
  55.          };
  56.          
  57.          tv_secs:  The number of seconds you want to wait before
  58.                    the time request should be completed.
  59.  
  60.          tv_micro: The number of microseconds. Note that the
  61.                    timer device is not very accurate. Your
  62.                    requests can be delayed by other programs
  63.                    running at the same time, but in the long
  64.                    run the timer device is accurate enough.
  65.  
  66.  
  67. As with all devices you have to connect a message port to
  68. the request block with which the timer device can talk to you.
  69. Create a message (reply) port by calling the CreatePort()
  70. function. Normally you should not use any name (the message
  71. port should not be made public) and priority set to 0 (normal
  72. priority).
  73.  
  74.   Synopsis: msg_port = CreatePort( name, pri );
  75.   
  76.   msg_port: (struct MsgPort *) Pointer to the new MsgPort
  77.             structure, or NULL if something went wrong.
  78.  
  79.   name:     (char *) Pointer to a string containing the name
  80.             of the message port, or NULL. When working with
  81.             devices you normally do not need to use any name.
  82.   
  83.   pri:      (BYTE) This message port's priority. Usually set
  84.             to 0 (normal priority).
  85.  
  86.  
  87. Once you have successfully opened a message port you may
  88. allocate and initialize the request block. Since the request
  89. block is "extended" (not the same size as the "standard" -
  90. IOStdReq structures) you need to use the CreateExtIO()
  91. function to allocate and initialize the request block.
  92. (Do not use the CreateStdIO() function!)
  93.  
  94.   Synopsis: ext_req = CreateExtIO( msg_port, size );
  95.  
  96.   ext_req:  (struct IORequest *) Pointer to the new extended
  97.             request block, or NULL if the request block could
  98.             not be created.
  99.  
  100.   msg_port: (struct MsgPort *) Pointer to the message port
  101.             the CreatePort() function returned. The timer
  102.             device will use it to send messages to you.
  103.  
  104.   size:     (long) The number of bytes that should be allocated
  105.             for the extended request block. Use the function
  106.             sizeof() to find the exact number of bytes needed.
  107.             Example: sizeof( struct timerequest ).
  108.  
  109.  
  110. Here is an example:
  111.  
  112.   /* The reply port: */
  113.   struct MsgPort *replymp;
  114.  
  115.   /* The timer request block: */
  116.   struct timerequest *timer_req;
  117.  
  118.   ...
  119.  
  120.  
  121.   /* Get a reply port: (No name, normal priority) */
  122.   replymp = (struct MsgPort *)
  123.     CreatePort( NULL, 0 );
  124.   if( !replymp )
  125.     clean_up( "Could not create the reply port!" );
  126.  
  127.   /* Allocate and preinitialize a request block: */
  128.   timer_req = (struct timerequest *)
  129.     CreateExtIO( replymp, sizeof(struct timerequest) );
  130.   if( !timer_req )
  131.     clean_up( "Could not create the request block!" );
  132.  
  133.  
  134.  
  135.  
  136. 2.2.2  OPEN THE TIMER DEVICE
  137.  
  138. Once you have successfully created a request block you can
  139. "open" the timer device. You should, however, first decide how
  140. accurate you want the timer device to be. The timer device can
  141. work in two different modes:
  142.  
  143.   1. The timer device can use the video beam to control its own
  144.      timer. This will make the timer very stable over long time
  145.      periods, but is not very accurate for short intervals
  146.      (less than one second).
  147.      
  148.      This mode is easy for the timer device to handle and thus
  149.      little computer time is used. This mode is called
  150.      "vertical blank timer" and the flag is "UNIT_VBLANK".
  151.  
  152.   2. If you want to use very short time periods (less than one
  153.      second) it can sometimes be necessary to use the special
  154.      CIA chips for the timer. The CIA chips has a much higher
  155.      "resolution" than the video beam, thus it will result in
  156.      very accurate time periods for short intervals. This mode
  157.      is more complicated than the vertical blank timer, and
  158.      more computer time is therefore used. This mode is called
  159.      "micro hertz timer" and the flag is "UNIT_MICROHZ"
  160.  
  161.  
  162. The general rule is that time periods longer than one second
  163. should use the vertical blank timer. Else, if really high
  164. "resolution" is needed, the micro hertz timer should be used.
  165.  
  166. Once you have decided which mode should be used you can open
  167. the timer device. No frills here, simply use the OpenDevice()
  168. function.
  169.  
  170.   Synopsis: error = OpenDevice( name, unit, req, flags );
  171.  
  172.   error:    (long) If OpenDevice() managed to open the timer
  173.             device it returns 0, else an error number is
  174.             returned.
  175.  
  176.   name:     (char *) Name of the device you want to open.
  177.             The name for the timer device has been defined
  178.             as "TIMERNAME" (header file "devices/timer.h").
  179.  
  180.   unit:     (long) Which timer mode you want the device to
  181.             use. Set this field to either "UNIT_VBLANK" or
  182.             "MICROHZ".
  183.  
  184.   req:      (struct IORequest *) Pointer to a previously
  185.             initialized request block.
  186.  
  187.   flags:    (long) Special flags which are ignored by the timer
  188.             device.
  189.  
  190.  
  191. Here is an example:
  192.  
  193.   /* Open the Timer Device: ("vertical blank timer") */
  194.   error = OpenDevice( TIMERNAME, UNIT_VBLANK, timer_req ,0 );
  195.   if( error )
  196.     clean_up( "Could not open the Timer Device!" );
  197.  
  198.  
  199.  
  200. 2.2.3  SET TIME REQUEST
  201.  
  202. When the timer device has been opened you can start to send your
  203. time requests. You specify the number of seconds and microseconds
  204. that should pass before a message will be sent by initializing
  205. the timeval structure. Note that the time you set is the minimum
  206. time. When the exact time has elapsed it may happen that some
  207. other program is for the moment occupying the processor, and
  208. thus the time message will be delayed for some microseconds.
  209.  
  210. You must also tell the device that you are sending a time
  211. request. You do it by setting the flag "TR_ADDREQUEST" in the
  212. "io_Command" field.
  213.  
  214. The request can now be sent to the device. Either use the DoIO()
  215. function if you want to wait for the request to be completed,
  216. or use the SendIO() function if you want your program to
  217. continue to run while the request is executed. See the previous
  218. chapter for a complete explanation on when and how the DoIO()
  219. and SendIO() functions should be used.
  220.  
  221. Here is an example:
  222.  
  223.   /* Set time: (5.25 seconds)*/
  224.   timer_req->tr_time.tv_secs = 5;
  225.   timer_req->tr_time.tv_micro = 250000;
  226.  
  227.   /* We want to add a time request: */
  228.   timer_req->tr_node.io_Command = TR_ADDREQUEST;
  229.  
  230.   /* Do our request and return when done:     */
  231.   /* (Our task is put to sleep for 5.25 sec.) */
  232.   DoIO( timer_req );
  233.  
  234.  
  235. If you want to send multiple requests you have to use several
  236. request blocks which each has been properly initialized. You
  237. must then also use the function SendIO() and not DoIO() since
  238. your program will else be put to sleep directly after the first
  239. request has been sent. See example 2.
  240.  
  241. Each time you send a request to the timer device all values in
  242. the timeval structure are destroyed. You must therefore always
  243. reinitialize these fields before you may repost the request to
  244. device.
  245.  
  246.  
  247.  
  248. 2.2.4  CLEAN UP
  249.  
  250. As always you must remember to clean up after you. All
  251. allocated request blocks must be removed, all opened message
  252. ports closed as well as all devices.
  253.  
  254. Fist you should close the timer device. Note that all requests
  255. you have posted to that device must either have been completed
  256. or aborted before you may close the device! All devices are
  257. closed by the special CloseDevice() function. 
  258.  
  259.   Synopsis: CloseDevice( req );
  260.  
  261.   reg:      (struct IORequest *) Pointer to the timer device's
  262.             own request block. (The same request block which
  263.             was used when you opened the timer device.)
  264.  
  265.  
  266. The request blocks are deleted by calling the DeleteExtIO()
  267. function. Note that the request must have been completed or
  268. aborted before you may delete it! Note also that you can not
  269. use the DeleteStdIO() function since the timer device is using
  270. extended request blocks.
  271.  
  272.   Synopsis: DeleteExtIO( std_req, size );
  273.  
  274.   std_req:  (struct IOStdReq *) Pointer to the request block
  275.             you want to delete.
  276.  
  277.   size:     (long) The size of the request block, in bytes.
  278.             Use the function sizeof() to get the correct number
  279.             of bytes. Example: sizeof( struct timerequest ).
  280.  
  281.  
  282. Finally you should close all message ports by calling the
  283. DeletePort() function. All messages must have been removed
  284. before you may close the message port.
  285.  
  286.   Synopsis: DeletePort( msg_port );
  287.  
  288.   msg_port: (struct MsgPort *) Pointer to the MsgPort structure
  289.             that should be deleted.
  290.  
  291.  
  292. Here is a short example:
  293.  
  294.   /* Close the Timer Device: */
  295.   CloseDevice( timer_req );
  296.  
  297.   /* Delete the request block: */
  298.   DeleteExtIO( timer_req, sizeof( struct timerequest) );
  299.  
  300.   /* Remove the message port: */
  301.   DeletePort( replymp );
  302.  
  303.  
  304.  
  305. 2.2.5  EXAMPLE
  306.  
  307. Here is a complete example on how to use the timer device. It
  308. will open a message port, create a request block, open the timer
  309. device, and finally put itself to sleep for 10 seconds. When the
  310. time has elapsed everything is returned and the program
  311. terminates. (Hmmm, very similar to example 1.)
  312.  
  313. #include <exec/types.h>    /* STRPTR         */
  314. #include <exec/ports.h>    /* struct Message */
  315. #include <exec/memory.h>   /* MEMF_PUBLIC    */
  316. #include <devices/timer.h> /* TIMERNAME */
  317.  
  318. /* The reply port: */
  319. struct MsgPort *replymp;
  320.  
  321. /* The timer request block: */
  322. struct timerequest *timer_req;
  323.  
  324. /* When the Timer Device is open this variable is TRUE: */
  325. BOOL not_opened = TRUE;
  326.  
  327. /* Declare our functions: */
  328. void clean_up();
  329. void main();
  330.  
  331. void main()
  332. {
  333.   /* 1. Get a reply port: */
  334.   replymp = (struct MsgPort *)
  335.     CreatePort( NULL, 0 );
  336.   if( !replymp )
  337.     clean_up( "Could not create the reply port!" );
  338.  
  339.   /* 2. Get an extended request block: */
  340.   timer_req = (struct timerequest *)
  341.     CreateExtIO( replymp, sizeof( struct timerequest) );
  342.   if( !timer_req )
  343.     clean_up( "Could not create the IO!" );
  344.  
  345.   /* 3. Open the Timer Device: */
  346.   not_opened = OpenDevice( TIMERNAME, UNIT_VBLANK, timer_req ,0 );
  347.   if( not_opened )
  348.     clean_up( "Could not open the Timer Device!" );
  349.  
  350.   /* 4. Set our request: */
  351.   timer_req->tr_node.io_Command = TR_ADDREQUEST; /* Add a request.   */
  352.   timer_req->tr_time.tv_secs = 10;               /* 10 seconds.      */
  353.   timer_req->tr_time.tv_micro = 0;               /* 0 micro seconds. */
  354.  
  355.   /* 5. Do our request: (Wait 10 seconds) */
  356.   printf( "Good night...\n" );
  357.   DoIO( timer_req );
  358.   printf( "Good morning!\n" );
  359.  
  360.   /* Clean up and quit: */
  361.   clean_up( "The End!" );
  362. }
  363.  
  364. void clean_up( text )
  365. STRPTR text;
  366. {
  367.   /* Close the Timer Device: */
  368.   if( !not_opened )
  369.     CloseDevice( timer_req );
  370.  
  371.   /* Delete the extended request block: */
  372.   if( timer_req )
  373.     DeleteExtIO( timer_req, sizeof( struct timerequest) );
  374.  
  375.   /* Remove the message port: */
  376.   if( replymp )
  377.     DeletePort( replymp);
  378.  
  379.   /* Print the last message: */
  380.   printf( "%s\n", text );
  381.  
  382.   /* Quit: */
  383.   exit( 0 );
  384. }
  385.  
  386.  
  387.  
  388. 2.3  SYSTEM TIME
  389.  
  390. The timer device can also be used to get the current system
  391. time. It should be noted that this system time has nothing to
  392. do with the Amiga's internal clock. The system time is simply
  393. a value which is initialized to the date when the boot disk was
  394. last modified. The value is relative to 1 January 1978,
  395. time 00:00:00.
  396.  
  397. Although it may not be a "correct" time value it can be useful.
  398. For example, if you want to adjust several time periods with
  399. each other it can be handy to have an external timer like the
  400. system time.
  401.  
  402. With help of the timer device you can both get the current
  403. system time as well as set it to a new value.
  404.  
  405.  
  406.  
  407. 2.3.1  GET SYSTEM TIME
  408.  
  409. To get the current system time you set the flag "TR_GETSYSTIME"
  410. in the io_Command field of the request block and send the
  411. request block to the timer device. When the timer device has
  412. completed the request it is returned and you may now examine the
  413. timeval structure where the current system time has been stored.
  414.  
  415. Each time you get the system time you will receive a value which
  416. is different from previous calls (it is an unique value).
  417.  
  418. Here is a short example:
  419.  
  420.   /* Get the current system time: */
  421.   timer_req->tr_node.io_Command = TR_GETSYSTIME;
  422.  
  423.   /* Do the request: */
  424.   DoIO( timer_req );
  425.  
  426.   /* Print the current system time: */
  427.   printf( "The current system time is:\n" );
  428.   printf( "Seconds:      %d\n", timer_req->tr_time.tv_secs );
  429.   printf( "Microseconds: %d\n", timer_req->tr_time.tv_micro );
  430.  
  431.  
  432.  
  433. 2.3.2  SET SYSTEM TIME
  434.  
  435. To set the system time to a new value simply set the
  436. "TR_SETSYSTIME" flag in the io_Command field of the request
  437. block, set the new time in the timeval structure, and finally
  438. send the request block to the timer device.
  439.  
  440. You may only set values that are greater than the current
  441. time. The timer device or other programs may be confused if
  442. the time suddenly went backwards.
  443.  
  444. Here is a short example:
  445.  
  446.   /* Add two hours and 0.4 seconds: */
  447.   tr->tr_time.tv_secs += 60 * 60 * 2;
  448.   tr->tr_time.tv_micro += 400000;
  449.  
  450.   /* Set the new system time: */
  451.   tr->tr_node.io_Command = TR_SETSYSTIME;
  452.  
  453.   /* Do the request: */
  454.   DoIO( tr );
  455.  
  456.  
  457.  
  458. 2.4  SPECIAL TIME FUNCTIONS
  459.  
  460. The timer device can also be used to compare different time
  461. reports and to add or subtract time values. To do these things
  462. the timer device contain three functions - CmpTime(), AddTime()
  463. and Subime(). Since these features are accessed as functions
  464. rather than using request blocks you have to prepare the timer
  465. device a little before you may use these functions.
  466.  
  467. The timer device is using a global pointer which is always
  468. called "TimerBase". This global pointer is used to find the
  469. starting address of the three special timer functions. Before
  470. you may use these functions you must therefore declare and
  471. initialize the TimerBase pointer. To initialize it simply use
  472. any request block which is connected to the timer device. In
  473. the "io_Device" field of the request block you will find the
  474. current address value of the timer device.
  475.  
  476. Here is a short example:
  477.  
  478.   /* Declare the global timer pointer: */
  479.   struct Device *TimerBase;
  480.  
  481.   /* ... create request blocks, open timer device etc ... */
  482.  
  483.   /* Get the global pointer to the timer device: */
  484.   TimerBase = timer_req->tr_node.io_Device;
  485.  
  486.  
  487. Once you have found the TimerBase pointer you may start to use
  488. the timer functions. Their primary usage is to coordinate
  489. different time requests with each other.
  490.  
  491.  
  492.  
  493. 2.4.1  COMPARE TIMES
  494.  
  495. The CmpTime() function is used to compare two timeval
  496. structures and returns 0 if they were identical, -1 if the
  497. first timeval structure was greater than the second, and
  498. 1 if the opposite (the second timeval structure was greater
  499. than the first).
  500.  
  501.   Synopsis: dif = CmpTime( time1, time2 );
  502.  
  503.   dif:      (long) If the two time values were identical 0 is
  504.             returned. If the first time value was greater than
  505.             the second time value -1 is returned, and if the
  506.             opposite (the second time value is greater than the
  507.             first time value) 1 is returned.
  508.  
  509.   time1:    (struct timeval *) Pointer to the first timeval
  510.             structure.
  511.  
  512.   time1:    (struct timeval *) Pointer to the second timeval
  513.             structure.
  514.  
  515.  
  516.  
  517. 2.4.2  ADD TIME
  518.  
  519. The AddTime() function is used to add the time in one timeval
  520. structure with the time in another timeval structure.
  521.  
  522.   Synopsis: AddTime( tiem1, time2 );
  523.  
  524.   time1:    (struct timeval *) Pointer to the first timeval
  525.             structure. The value of the second timeval
  526.             structure will be added with this timeval
  527.             structure, and the result stored here.
  528.  
  529.   time1:    (struct timeval *) Pointer to the second timeval
  530.             structure.
  531.  
  532.  
  533.  
  534. 2.4.3  SUBTRACT TIME
  535.  
  536. The SubTime() function is used to subtract the time in one timeval
  537. structure with the time in another timeval structure.
  538.  
  539.   Synopsos: SubTime( tiem1, time2 );
  540.  
  541.   time1:    (struct timeval *) Pointer to the first timeval
  542.             structure. The value of the second timeval
  543.             structure will be subtracted with this timeval
  544.             structure, and the result stored here.
  545.  
  546.   time1:    (struct timeval *) Pointer to the second timeval
  547.             structure.
  548.  
  549.  
  550.  
  551. 2.4.5  EXAMPLE
  552.  
  553. This short example demonstrates how to use the timer device's
  554. own functions. ("tr1", "tr2" and "tr3" are three already
  555. initialized requst blocks.)
  556.  
  557.   /* Set the times: */
  558.   /* Request 1: */
  559.   tr1->tr_time.tv_secs = 10;
  560.   tr1->tr_time.tv_micro = 0;
  561.   /* Request 2: */
  562.   tr2->tr_time.tv_secs =  7;
  563.   tr2->tr_time.tv_micro = 0;
  564.   /* Request 3: */
  565.   tr3->tr_time.tv_secs =  5;
  566.   tr3->tr_time.tv_micro = 0;
  567.  
  568.   /* Get a pointer to the timer device: */
  569.   TimerBase = tr1->tr_node.io_Device;
  570.  
  571.   /* Compare the first two time val structures: */
  572.   printf( "Compare time1 - time2: %d\n",
  573.     CmpTime( &(tr1->tr_time), &(tr2->tr_time) ) );
  574.  
  575.   /* Add the time in the third timeval structure to   */
  576.   /* the second timeval structure. The second timeval */
  577.   /* structure should now contain the time 12 sec.    */
  578.   AddTime( &(tr2->tr_time), &(tr3->tr_time) );
  579.  
  580.   /* Subtract the time in the third timeval structure with  */
  581.   /* the second timeval structure. The second timeval       */
  582.   /* structure should now again contain the time 7 seconds. */
  583.   SubTime( &(tr2->tr_time), &(tr3->tr_time) );
  584.  
  585.  
  586. Note that we have to use pointers to the timeval structures
  587. as arguments [&(tr1->tr_time]. The parentheses around the
  588. expression are actually unnecessary since the "->" operator
  589. already has higher priority than the "&" operator. However,
  590. this makes it easier to read.
  591.  
  592.  
  593.  
  594. 2.5  FUNCTIONS
  595.  
  596. The functions DoIO(), SendIO(), WaitIO(), AbortIO() etc...
  597. have already been defined in the previous chapter, and I
  598. will therefore not repeat all this information here.
  599.  
  600. There exist three functions which are supported by the timer
  601. device. Before you may use them you have to initialize a
  602. global pointer named "TimerBase". (See above for more
  603. information.)
  604.  
  605.  
  606. CmpTime()
  607.  
  608.   The CmpTime() function is used to compare two timeval
  609.   structures and returns 0 if they were identical, -1 if the
  610.   first timeval structure was greater than the second, and
  611.   1 if the opposite (the second timeval structure was greater
  612.   than the first).
  613.  
  614.   Synopsis: dif = CmpTime( time1, time2 );
  615.  
  616.   dif:      (long) If the two time values were identical 0 is
  617.             returned. If the first time value was greater than
  618.             the second time value -1 is returned, and if the
  619.             opposite (the second time value is greater than the
  620.             first time value) 1 is returned.
  621.  
  622.   time1:    (struct timeval *) Pointer to the first timeval
  623.             structure.
  624.  
  625.   time1:    (struct timeval *) Pointer to the second timeval
  626.             structure.
  627.  
  628.  
  629. AddTime()
  630.  
  631.   The AddTime() function is used to add the time in one timeval
  632.   structure with the time in another timeval structure.
  633.  
  634.   Synopsis: AddTime( tiem1, time2 );
  635.  
  636.   time1:    (struct timeval *) Pointer to the first timeval
  637.             structure. The value of the second timeval
  638.             structure will be added with this timeval
  639.             structure, and the result stored here.
  640.  
  641.   time1:    (struct timeval *) Pointer to the second timeval
  642.             structure.
  643.  
  644.  
  645. SubTime()
  646.  
  647.   The SubTime() function is used to subtract the time in one
  648.   timeval structure with the time in another timeval structure.
  649.  
  650.   Synopsos: SubTime( tiem1, time2 );
  651.  
  652.   time1:    (struct timeval *) Pointer to the first timeval
  653.             structure. The value of the second timeval
  654.             structure will be subtracted with this timeval
  655.             structure, and the result stored here.
  656.  
  657.   time1:    (struct timeval *) Pointer to the second timeval
  658.             structure.
  659.  
  660.  
  661.  
  662. 2.6  EXAMPLES
  663.  
  664. Example 1
  665.   This example demonstrates how you can use the Timer Device.
  666.   The program will be put to sleep for 10 seconds.
  667.  
  668. Example 2
  669.   This example demonstrates how you can send several requests
  670.   to the Timer Device.
  671.  
  672. Example 3
  673.   This example demonstrates how you can use the Timer Device
  674.   to get the current system time. We will then add two hours
  675.   and set the new system time.
  676.  
  677. Example 4
  678.   This example demonstrates how you can compare, add and
  679.   subtract time values with help of the timer device's own
  680.   functions.
  681.  
  682.  
  683.