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