00001 #ifndef OSCL_TIMER_H_INCLUDED
00002 #define OSCL_TIMER_H_INCLUDED
00003
00004 #ifndef OSCL_BASE_H_INCLUDED
00005 #include "oscl_base.h"
00006 #endif
00007
00008 #ifndef OSCLCONFIG_UTIL_H_INCLUDED
00009 #include "osclconfig_util.h"
00010 #endif
00011
00012 #ifndef OSCL_VECTOR_H_INCLUDED
00013 #include "oscl_vector.h"
00014 #endif
00015
00016 #ifndef OSCL_TICKCOUNT_H_INCLUDED
00017 #include "oscl_tickcount.h"
00018 #endif
00019
00020 #ifndef OSCL_RAND_H_INCLUDED
00021 #include "oscl_rand.h"
00022 #endif
00023
00024 #ifndef OSCL_SCHEDULER_AO_H_INCLUDED
00025 #include "oscl_scheduler_ao.h"
00026 #endif
00027
00028
00032 class OsclTimerObserver
00033 {
00034 public:
00043 virtual void TimeoutOccurred(int32 timerID, int32 timeoutInfo) = 0;
00044
00045 virtual ~OsclTimerObserver() {}
00046 };
00047
00053 template<class Alloc>
00054 class OsclTimer ;
00055
00056 class CallbackTimerObserver
00057 {
00058 public:
00059 virtual void TimerBaseElapsed() = 0;
00060 virtual ~CallbackTimerObserver() {}
00061 };
00062
00063 template<class Alloc>
00064 class CallbackTimer: public OsclTimerObject
00065 {
00066 public:
00067 CallbackTimer(CallbackTimerObserver& aContainer, const char *name, int32 aPriority = OsclActiveObject::EPriorityNominal)
00068 : OsclTimerObject(aPriority, name)
00069 {
00070 iContainer = &aContainer;
00071 AddToScheduler();
00072 }
00073 ~CallbackTimer()
00074 {
00075 RemoveFromScheduler();
00076 }
00077 void Run()
00078 {
00079 if (Status() == OSCL_REQUEST_ERR_NONE)
00080 iContainer->TimerBaseElapsed();
00081 }
00082 private:
00083 CallbackTimerObserver *iContainer;
00084 };
00085
00086
00087 template<class Alloc>
00088 class OsclTimer : public CallbackTimerObserver
00089 {
00090 public:
00091
00092 typedef CallbackTimer<Alloc> callback_timer_type;
00093
00100 OsclTimer(const char *name, uint32 frequency = 1, int32 priority = OsclActiveObject::EPriorityNominal);
00101 virtual ~OsclTimer();
00102
00109 void SetObserver(OsclTimerObserver *obs)
00110 {
00111 iObserver = obs;
00112 }
00119 void SetFrequency(uint32 frequency);
00120
00127 void SetExactFrequency(uint32 frequency);
00128
00142 void Request(int32 timerID, int32 timeoutInfo, int32 cycles, OsclTimerObserver *obs = 0, bool recurring = 0);
00151 void Cancel(int32 timerID, int32 timeoutInfo = -1);
00155 void Clear();
00156
00157 private:
00158
00159
00160 callback_timer_type *iTimer;
00161
00162 typedef struct _TimerEntry
00163 {
00164 int32 iCounter ;
00165 int32 iTimerID ;
00166 int32 iParam ;
00167 OsclTimerObserver *iObserver;
00168 bool iRecurring;
00169 int32 iOrigCounter;
00170 } TimerEntry;
00171
00172 typedef TimerEntry entry_type;
00173 typedef Oscl_Vector<entry_type*, Alloc> entries_type;
00174 typedef typename entries_type::iterator entries_type_iterator;
00175
00176 OsclTimerObserver *iObserver;
00177 entries_type iEntries;
00178 entries_type iEntriesWaitingToAdd;
00179 entries_type iEntriesWaitingToCancel;
00180 Oscl_TAlloc<entry_type, Alloc> iEntryAllocator;
00181
00182 bool iInCallback;
00183
00184 uint32 iCyclePeriod;
00185 uint32 iTickCountPeriod;
00186 uint32 iExpectedTimeout;
00187
00188 protected:
00189 void TimerBaseElapsed();
00190 friend class CallbackTimer<Alloc>;
00191 };
00192
00193 template<class Alloc>
00194 OsclTimer<Alloc>::OsclTimer(const char *name, uint32 frequency, int32 priority) :
00195 iObserver(0)
00196 , iInCallback(false)
00197 , iTickCountPeriod(0)
00198 , iExpectedTimeout(0)
00199 {
00200
00201 Alloc alloc;
00202 iTimer = OSCL_PLACEMENT_NEW(alloc.ALLOCATE(sizeof(CallbackTimer<Alloc>)), CallbackTimer<Alloc>(*this, name, priority));
00203 SetFrequency(frequency);
00204 }
00205
00206 template<class Alloc>
00207 OsclTimer<Alloc>::~OsclTimer()
00208 {
00209
00210 if (iTimer)
00211 iTimer->Cancel();
00212 if (iTimer)
00213 {
00214 iTimer->OSCL_TEMPLATED_DESTRUCTOR_CALL(callback_timer_type, CallbackTimer);
00215 Alloc alloc;
00216 alloc.deallocate(iTimer);
00217 }
00218 iTimer = NULL;
00219
00220 for (entries_type_iterator it = iEntries.begin(); it != iEntries.end(); it++)
00221 {
00222 iEntryAllocator.deallocate(*it);
00223 }
00224 }
00225
00226 template<class Alloc>
00227 void OsclTimer<Alloc>::SetFrequency(uint32 frequency)
00228 {
00229
00230 iCyclePeriod = 1000000 / frequency;
00231
00232 iTickCountPeriod = OsclTickCount::TickCountPeriod();
00233 }
00234
00235 template<class Alloc>
00236 void OsclTimer<Alloc>::SetExactFrequency(uint32 frequency)
00237 {
00238
00239 iCyclePeriod = frequency;
00240
00241 iTickCountPeriod = OsclTickCount::TickCountPeriod();
00242 }
00243
00244
00245 template<class Alloc>
00246 void OsclTimer<Alloc>::Request(int32 timerID, int32 param, int32 cycles, OsclTimerObserver *obs, bool recurring)
00247 {
00248
00249
00250 entry_type *entry = iEntryAllocator.ALLOCATE(1);
00251 entry->iTimerID = timerID;
00252 entry->iParam = param;
00253 entry->iCounter = cycles;
00254 entry->iObserver = obs;
00255 entry->iRecurring = recurring;
00256 entry->iOrigCounter = entry->iCounter;
00257
00258
00259 if (iInCallback)
00260 {
00261 iEntriesWaitingToAdd.push_back(entry);
00262 return;
00263 }
00264
00265 iEntries.push_back(entry);
00266
00267 if (iTimer)
00268 {
00269 iTimer->RunIfNotReady(iCyclePeriod);
00270 }
00271
00272 if (iExpectedTimeout == 0)
00273 {
00274 iExpectedTimeout = (OsclTickCount::TickCount() * iTickCountPeriod) + iCyclePeriod;
00275 }
00276 }
00277
00278
00279 template<class Alloc>
00280 void OsclTimer<Alloc>::Cancel(int32 timerID, int32 param)
00281 {
00282
00283 if (iInCallback)
00284 {
00285
00286 entry_type *entry = iEntryAllocator.ALLOCATE(1);
00287 entry->iTimerID = timerID;
00288 entry->iParam = param;
00289
00290 iEntriesWaitingToCancel.push_back(entry);
00291 return;
00292 }
00293
00294
00295 for (entries_type_iterator it = iEntries.begin(); it != iEntries.end(); it++)
00296 {
00297 if ((*it)->iTimerID == timerID)
00298 {
00299
00300 if ((*it)->iParam == param || param == -1)
00301 {
00302 iEntryAllocator.deallocate(*it);
00303 iEntries.erase(it);
00304 return;
00305 }
00306 }
00307 }
00308 }
00309
00310
00311 template<class Alloc>
00312 void OsclTimer<Alloc>::Clear()
00313 {
00314 for (entries_type_iterator it = iEntries.begin(); it != iEntries.end(); it++)
00315 {
00316 iEntryAllocator.deallocate(*it);
00317 }
00318 iEntries.clear();
00319 }
00320
00321 template<class Alloc>
00322 void OsclTimer<Alloc>::TimerBaseElapsed()
00323 {
00324 uint8 expiredFound = 0;
00325
00326 {
00327
00328 for (entries_type_iterator it = iEntries.begin(); it != iEntries.end(); it++)
00329 {
00330 entry_type *entry = (*it);
00331 if (--(entry->iCounter) <= 0)
00332 {
00333 if (!entry->iRecurring) expiredFound = 1;
00334 if (entry->iRecurring) entry->iCounter = entry->iOrigCounter;
00335
00336
00337 OsclTimerObserver *obs = (entry->iObserver ? entry->iObserver : iObserver);
00338 if (obs)
00339 {
00340 iInCallback = true;
00341 obs->TimeoutOccurred(entry->iTimerID, entry->iParam);
00342 iInCallback = false;
00343 }
00344 }
00345 }
00346 }
00347
00348
00349 while (expiredFound)
00350 {
00351 expiredFound = 0;
00352 for (entries_type_iterator it = iEntries.begin(); it != iEntries.end(); it++)
00353 {
00354 entry_type *entry = (*it);
00355 if (entry->iCounter <= 0)
00356 {
00357 expiredFound = 1;
00358 iEntryAllocator.deallocate(entry);
00359 iEntries.erase(it);
00360 break;
00361 }
00362 }
00363 }
00364
00365 {
00366
00367 for (entries_type_iterator it = iEntriesWaitingToCancel.begin(); it != iEntriesWaitingToCancel.end(); it++)
00368 {
00369 entry_type *entry = (*it);
00370 Cancel(entry->iTimerID, entry->iParam);
00371 iEntryAllocator.deallocate(entry);
00372 }
00373 iEntriesWaitingToCancel.clear();
00374 }
00375
00376 {
00377
00378 for (entries_type_iterator it = iEntriesWaitingToAdd.begin(); it != iEntriesWaitingToAdd.end(); it++)
00379 {
00380 entry_type *entry = (*it);
00381 Request(entry->iTimerID, entry->iParam, entry->iCounter, entry->iObserver);
00382 iEntryAllocator.deallocate(entry);
00383 }
00384 iEntriesWaitingToAdd.clear();
00385 }
00386
00387 if (!iEntries.empty())
00388 {
00389
00390 uint32 time = OsclTickCount::TickCount() * iTickCountPeriod;
00391 int32 jitter = time - iExpectedTimeout;
00392 int32 waitperiod = iCyclePeriod - jitter;
00393
00394
00395
00396
00397 if ((uint)OSCL_ABS(jitter) > iCyclePeriod)
00398 {
00399 iExpectedTimeout = time;
00400 }
00401 else
00402 {
00403 iExpectedTimeout += iCyclePeriod;
00404 }
00405
00406 waitperiod = OSCL_MAX(waitperiod, 0);
00407
00408 if (iTimer)
00409 {
00410 iTimer->RunIfNotReady(waitperiod);
00411 }
00412 }
00413 else
00414 {
00415 iExpectedTimeout = 0;
00416 }
00417 }
00418
00419
00420
00421 #endif