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

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     if (frequency == 0)
00201     {
00202         OSCL_LEAVE(OsclErrArgument);
00203     }
00204     else
00205     {
00206         //use the allocator with placement 'new'
00207         Alloc alloc;
00208         iTimer = OSCL_PLACEMENT_NEW(alloc.ALLOCATE(sizeof(CallbackTimer<Alloc>)), CallbackTimer<Alloc>(*this, name, priority));
00209         SetFrequency(frequency);
00210     }
00211 }
00212 
00213 template<class Alloc>
00214 OsclTimer<Alloc>::~OsclTimer()
00215 {
00216     // Make sure we're cancelled
00217     if (iTimer)
00218         iTimer->Cancel();
00219     if (iTimer)
00220     {
00221         iTimer->OSCL_TEMPLATED_DESTRUCTOR_CALL(callback_timer_type, CallbackTimer);
00222         Alloc alloc;
00223         alloc.deallocate(iTimer);
00224     }
00225     iTimer = NULL;
00226 
00227     for (entries_type_iterator it = iEntries.begin(); it != iEntries.end(); it++)
00228     {
00229         iEntryAllocator.deallocate(*it);
00230     }
00231 }
00232 
00233 template<class Alloc>
00234 void OsclTimer<Alloc>::SetFrequency(uint32 frequency)
00235 {
00236     // timer takes microseconds
00237     iCyclePeriod = 1000000 / frequency;
00238     // get tick count period
00239     iTickCountPeriod = OsclTickCount::TickCountPeriod();
00240 }
00241 
00242 template<class Alloc>
00243 void OsclTimer<Alloc>::SetExactFrequency(uint32 frequency)
00244 {
00245     // timer takes microseconds
00246     iCyclePeriod = frequency;
00247     // get tick count period
00248     iTickCountPeriod = OsclTickCount::TickCountPeriod();
00249 }
00250 
00251 // Request a timer
00252 template<class Alloc>
00253 void OsclTimer<Alloc>::Request(int32 timerID, int32 param, int32 cycles, OsclTimerObserver *obs, bool recurring)
00254 {
00255 
00256     // add to list of timers
00257     entry_type *entry = iEntryAllocator.ALLOCATE(1);
00258     entry->iTimerID = timerID;
00259     entry->iParam = param;
00260     entry->iCounter = cycles;
00261     entry->iObserver = obs;
00262     entry->iRecurring = recurring;
00263     entry->iOrigCounter = entry->iCounter;
00264 
00265     // if the request is called inside of a callback, then we must add it later
00266     if (iInCallback)
00267     {
00268         iEntriesWaitingToAdd.push_back(entry);
00269         return;
00270     }
00271 
00272     iEntries.push_back(entry);
00273 
00274     if (iTimer)
00275     {
00276         iTimer->RunIfNotReady(iCyclePeriod);
00277     }
00278 
00279     if (iExpectedTimeout == 0)
00280     {
00281         iExpectedTimeout = (OsclTickCount::TickCount() * iTickCountPeriod) + iCyclePeriod;
00282     }
00283 }
00284 
00285 // Cancel a timer
00286 template<class Alloc>
00287 void OsclTimer<Alloc>::Cancel(int32 timerID, int32 param)
00288 {
00289 
00290     if (iInCallback)
00291     {
00292         // add to list of timers
00293         entry_type *entry = iEntryAllocator.ALLOCATE(1);
00294         entry->iTimerID = timerID;
00295         entry->iParam = param;
00296 
00297         iEntriesWaitingToCancel.push_back(entry);
00298         return;
00299     }
00300 
00301     // remove from list of timers
00302     for (entries_type_iterator it = iEntries.begin(); it != iEntries.end(); it++)
00303     {
00304         if ((*it)->iTimerID == timerID)
00305         {
00306             // make sure the param matches unless it is not specified (-1)
00307             if ((*it)->iParam == param || param == -1)
00308             {
00309                 iEntryAllocator.deallocate(*it);
00310                 iEntries.erase(it);
00311                 return;
00312             }
00313         }
00314     }
00315 }
00316 
00317 // Clear all waiting timers
00318 template<class Alloc>
00319 void OsclTimer<Alloc>::Clear()
00320 {
00321     for (entries_type_iterator it = iEntries.begin(); it != iEntries.end(); it++)
00322     {
00323         iEntryAllocator.deallocate(*it);
00324     }
00325     iEntries.clear();
00326 }
00327 
00328 template<class Alloc>
00329 void OsclTimer<Alloc>::TimerBaseElapsed()
00330 {
00331     uint8 expiredFound = 0;
00332 
00333     {
00334         // call all whose timers have expired
00335         for (entries_type_iterator it = iEntries.begin(); it != iEntries.end(); it++)
00336         {
00337             entry_type *entry = (*it);
00338             if (--(entry->iCounter) <= 0)
00339             {
00340                 if (!entry->iRecurring) expiredFound = 1;
00341                 if (entry->iRecurring) entry->iCounter = entry->iOrigCounter;
00342 
00343                 // use local observer if it exists, otherwise use global observer
00344                 OsclTimerObserver *obs = (entry->iObserver ? entry->iObserver : iObserver);
00345                 if (obs)
00346                 {
00347                     iInCallback = true;
00348                     obs->TimeoutOccurred(entry->iTimerID, entry->iParam);
00349                     iInCallback = false;
00350                 }
00351             }
00352         }
00353     }
00354 
00355     // remove from list all whose timers have expired
00356     while (expiredFound)
00357     {
00358         expiredFound = 0;
00359         for (entries_type_iterator it = iEntries.begin(); it != iEntries.end(); it++)
00360         {
00361             entry_type *entry = (*it);
00362             if (entry->iCounter <= 0)
00363             {
00364                 expiredFound = 1;
00365                 iEntryAllocator.deallocate(entry);
00366                 iEntries.erase(it);
00367                 break;
00368             }
00369         }
00370     }
00371 
00372     {
00373         // if any timers were cancelled in the callback, process them now
00374         for (entries_type_iterator it = iEntriesWaitingToCancel.begin(); it != iEntriesWaitingToCancel.end(); it++)
00375         {
00376             entry_type *entry = (*it);
00377             Cancel(entry->iTimerID, entry->iParam);
00378             iEntryAllocator.deallocate(entry);
00379         }
00380         iEntriesWaitingToCancel.clear();
00381     }
00382 
00383     {
00384         // if any timers were requested in the callback, process them now
00385         for (entries_type_iterator it = iEntriesWaitingToAdd.begin(); it != iEntriesWaitingToAdd.end(); it++)
00386         {
00387             entry_type *entry = (*it);
00388             Request(entry->iTimerID, entry->iParam, entry->iCounter, entry->iObserver);
00389             iEntryAllocator.deallocate(entry);
00390         }
00391         iEntriesWaitingToAdd.clear();
00392     }
00393 
00394     if (!iEntries.empty())
00395     {
00396         // adjust for the jitter
00397         uint32 time = OsclTickCount::TickCount() * iTickCountPeriod;
00398         int32 jitter = time - iExpectedTimeout;
00399         int32 waitperiod = iCyclePeriod - jitter;
00400 
00401         // currently there is some problem on the phone if we send
00402         // in real-time rather than with a slower (growing delay) H.223 mux output
00403         // if jitter is too large in either direction, start over
00404         if ((uint)OSCL_ABS(jitter) > iCyclePeriod)
00405         {
00406             iExpectedTimeout = time;
00407         }
00408         else
00409         {
00410             iExpectedTimeout += iCyclePeriod;
00411         }
00412 
00413         waitperiod = OSCL_MAX(waitperiod, 0);
00414 
00415         if (iTimer)
00416         {
00417             iTimer->RunIfNotReady(waitperiod);
00418         }
00419     }
00420     else
00421     {
00422         iExpectedTimeout = 0;
00423     }
00424 }
00425 
00426 
00427 
00428 #endif

OSCL API
Posting Version: CORE_8.000.1.1_RC4