Main Page   Modules   Class Hierarchy   Data Structures   File List   Data Fields   Globals  

oscl_timer.h

Go to the documentation of this file.
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         //Note: the timer needs to be a new'd object so that
00159         //the CBase construction zeros the memory.
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     //use the allocator with placement 'new'
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     // Make sure we're cancelled
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     // timer takes microseconds
00230     iCyclePeriod = 1000000 / frequency;
00231     // get tick count period
00232     iTickCountPeriod = OsclTickCount::TickCountPeriod();
00233 }
00234 
00235 template<class Alloc>
00236 void OsclTimer<Alloc>::SetExactFrequency(uint32 frequency)
00237 {
00238     // timer takes microseconds
00239     iCyclePeriod = frequency;
00240     // get tick count period
00241     iTickCountPeriod = OsclTickCount::TickCountPeriod();
00242 }
00243 
00244 // Request a timer
00245 template<class Alloc>
00246 void OsclTimer<Alloc>::Request(int32 timerID, int32 param, int32 cycles, OsclTimerObserver *obs, bool recurring)
00247 {
00248 
00249     // add to list of timers
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     // if the request is called inside of a callback, then we must add it later
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 // Cancel a timer
00279 template<class Alloc>
00280 void OsclTimer<Alloc>::Cancel(int32 timerID, int32 param)
00281 {
00282 
00283     if (iInCallback)
00284     {
00285         // add to list of timers
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     // remove from list of timers
00295     for (entries_type_iterator it = iEntries.begin(); it != iEntries.end(); it++)
00296     {
00297         if ((*it)->iTimerID == timerID)
00298         {
00299             // make sure the param matches unless it is not specified (-1)
00300             if ((*it)->iParam == param || param == -1)
00301             {
00302                 iEntryAllocator.deallocate(*it);
00303                 iEntries.erase(it);
00304                 return;
00305             }
00306         }
00307     }
00308 }
00309 
00310 // Clear all waiting timers
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         // call all whose timers have expired
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                 // use local observer if it exists, otherwise use global observer
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     // remove from list all whose timers have expired
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         // if any timers were cancelled in the callback, process them now
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         // if any timers were requested in the callback, process them now
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         // adjust for the jitter
00390         uint32 time = OsclTickCount::TickCount() * iTickCountPeriod;
00391         int32 jitter = time - iExpectedTimeout;
00392         int32 waitperiod = iCyclePeriod - jitter;
00393 
00394         // currently there is some problem on the phone if we send
00395         // in real-time rather than with a slower (growing delay) H.223 mux output
00396         // if jitter is too large in either direction, start over
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

OSCL API
Posting Version: OPENCORE_20090310