00001 // From O'Reilly
00002
00003 enum TimerState { Idle, Active, Done };
00004 enum TimerType { OneShot, Periodic };
00005
00006 class Timer
00007 {
00008 public:
00009 Timer();
00010 virtual ~Timer();
00011
00012 int start( unsigned int nMilliseconds, TimerType =OneShot);
00013 int waitfor();
00014 void cancel();
00015
00016 volatile TimerState state; // Changed by some other process.
00017 TimerType type;
00018
00019 ULONG length;
00020
00021 ULONG count; // The number of ticks remaining.
00022 Timer* pNext; // For a Linked List of Timer
00023 // Ordered by the number of ticks
00024 // remaining for each timer.
00025
00026 private:
00027 // It's static because it can't manipulate software timer variable
00028 // Our interrupt service routine.
00029 static void interrupt Interrupt();
00030 };
00031
00032 #include "i8018xEB.h" // Declare the gProcessor global object
00033 #include "Timer.hpp"
00034
00035 #define CYCLES_PER_TICK (25000/4)
00036 /* Number of clock cycles per tick.
00037 for a 25 MHz => 25,000,000 cycles/s OR 25,000 cycles/ms
00038 and a tick takes 4 ms.
00039
00040 The software timer can have a duration from 1 to 65,535 ms,
00041 a bit more than a minute.
00042 */
00043
00044
00045 /**************************************************************************
00046 * *
00047 * Method: Timer() *
00048 * Description: Constructor for the Timer Class. *
00049 * *
00050 * Returns: None defined. *
00051 * *
00052 **************************************************************************/
00053
00054 Timer::Timer (void)
00055 {
00056 static int bInitialized = 0;
00057
00058 // Initialize the new software timer.
00059
00060 state = Idle;
00061 type = OneShot;
00062 length = 0;
00063 count = 0;
00064 pNext = NULL;
00065
00066 // Initialize the timer hardware, if not previously done.
00067
00068 if ( !bInitialized )
00069 {
00070 // Install the interrupt handler and enable timer interrupts.
00071 gProcessor.installHandler( TIMER2_INT, Timer::Interrupt);
00072 gProcessor.pPCB->intControl.timerControl &= ~(TIMER_MASK | TIMER_PRIORITY );
00073
00074 // Initialize the hardware device (using Timer #2)
00075 gProcessor.pPCB->timer[2].count = 0;
00076 gProcessor.pPCB->timer[2].maxCountA = CYCLES_PER_TICK;
00077 gProcessor.pPCB->timer[2].control = TIMER_ENABLE | TIMER_INTERRUPT | TIMER_PERIODIC;
00078
00079 // Mark the timer hardware initialized.
00080 bInitialized = 1;
00081 }
00082
00083 } /* Timer constructor */
00084
00085 /**************************************************************************
00086 * *
00087 * Method: Start() *
00088 * Description: Start a software timer, based on the tick *
00089 * from the underlying hardware timer. *
00090 * *
00091 * Returns: 0 on success, -1 if the timer is already in use. *
00092 * *
00093 **************************************************************************/
00094
00095 int Timer::start( unsigned int nMilliseconds, TimerType timerType )
00096 {
00097 if ( state != Idle ) { // Timer already in use.
00098 return (-1);
00099 }
00100
00101 // Initialize the software timer.
00102 state = Active;
00103 type = timerType;
00104 length = nMilliseconds / MS_PER_TICK;
00105
00106 // Add this timer to the active timer list.
00107 timerList.insert( this );
00108
00109 return (0);
00110
00111 } /* start() */
00112
00113 /**************************************************************************
00114 * *
00115 * Method: Interrupt() *
00116 * Description: An interrupt handler for the timer hardware *
00117 * *
00118 * Notes: - This method is declared static, so that we cannot *
00119 * inadvertently modify any of the software timers. *
00120 * - The keyword interrupt is to ask a x86 compiler *
00121 * to save and restore every registers before and after *
00122 * that specific method (more than ordinary method call). *
00123 * *
00124 * Returns: None defined. *
00125 * *
00126 **************************************************************************/
00127 void interrupt Timer::Interrupt()
00128 {
00129 // Decrement the active timer's count.
00130 timerList.tick();
00131
00132 // Acknowledge the timer interrupt.
00133 gProcessor.pPCB->intControl.eoi = EOI_NONSPECIFIC;
00134
00135 // Clear the Maximum Count bit (to start the next cycle).
00136 gProcessor.pPCB->timer[2].control &= ~TIMER_MAXCOUNT;
00137
00138 } /* Interrupt() */
00139
00140 /**************************************************************************
00141 * *
00142 * Method: waitfor() *
00143 * Description: Wait for the software timer to finish. *
00144 * *
00145 * Returns: 0 on success, -1 if the timer is not running. *
00146 * *
00147 **************************************************************************/
00148 int Timer::waitfor()
00149 {
00150 if (state != Active)
00151 {
00152 return (-1);
00153 }
00154
00155 // Wait for the timer to expire in a stupid busy-loop.
00156 while ( state != Done);
00157
00158 // Restart or idle the timer, depending on its type.
00159 if ( type == Periodic )
00160 {
00161 state = Active;
00162 timerList.insert( this );
00163 }
00164 else
00165 {
00166 state = Idle;
00167 }
00168
00169 return (0);
00170
00171 } /* waitfor() */
00172
00173 /**************************************************************************
00174 * *
00175 * Method: cancel() *
00176 * Description: Stop a running timer *
00177 * *
00178 * Returns: None defined. *
00179 * *
00180 **************************************************************************/
00181 void Timer::cancel( void )
00182 {
00183 // Remove the timer from the timer list.
00184 if ( state == Active )
00185 {
00186 timerList.remove( this );
00187 }
00188
00189 // Reset the timer's state.
00190 state = Idle;
00191
00192 } /* cancel() */
00193
00194 Timer::~Timer()
00195 {
00196 cancel();
00197 }
00198
00199 // Careful with Periodic timer that waitfor is never called.
00200 int Timer::poll()
00201 {
00202 return ( state == Done );
00203 }
00204
00205 // Asynchronous CallBack
00206
00207
00208
1.2.11.1 written by Dimitri van Heesch,
© 1997-2001