1/* ------------------------------------------------------------------ 2 * Copyright (C) 1998-2009 PacketVideo 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 13 * express or implied. 14 * See the License for the specific language governing permissions 15 * and limitations under the License. 16 * ------------------------------------------------------------------- 17 */ 18#ifndef OSCL_TIMER_H_INCLUDED 19#define OSCL_TIMER_H_INCLUDED 20 21#ifndef OSCL_BASE_H_INCLUDED 22#include "oscl_base.h" 23#endif 24 25#ifndef OSCLCONFIG_UTIL_H_INCLUDED 26#include "osclconfig_util.h" 27#endif 28 29#ifndef OSCL_VECTOR_H_INCLUDED 30#include "oscl_vector.h" 31#endif 32 33#ifndef OSCL_TICKCOUNT_H_INCLUDED 34#include "oscl_tickcount.h" 35#endif 36 37#ifndef OSCL_RAND_H_INCLUDED 38#include "oscl_rand.h" 39#endif 40 41#ifndef OSCL_SCHEDULER_AO_H_INCLUDED 42#include "oscl_scheduler_ao.h" 43#endif 44 45 46/** 47 * The observer class to receive timeout callbacks 48 */ 49class OsclTimerObserver 50{ 51 public: 52 /** 53 * This function will be called when the timer associated 54 * with this observer is executed 55 * 56 * @param timerID The ID given at timer request. 57 * @param timeoutInfo 58 * Any extra info given at timer request. 59 */ 60 virtual void TimeoutOccurred(int32 timerID, int32 timeoutInfo) = 0; 61 62 virtual ~OsclTimerObserver() {} 63}; 64 65/** 66 * A timer class for scheduling one or more timeout events. 67 * The timeout event will trigger a callback to an observer 68 * class. 69 */ 70template<class Alloc> 71class OsclTimer ; 72 73class CallbackTimerObserver 74{ 75 public: 76 virtual void TimerBaseElapsed() = 0; 77 virtual ~CallbackTimerObserver() {} 78}; 79 80template<class Alloc> 81class CallbackTimer: public OsclTimerObject 82{ 83 public: 84 CallbackTimer(CallbackTimerObserver& aContainer, const char *name, int32 aPriority = OsclActiveObject::EPriorityNominal) 85 : OsclTimerObject(aPriority, name) 86 { 87 iContainer = &aContainer; 88 AddToScheduler(); 89 } 90 ~CallbackTimer() 91 { 92 RemoveFromScheduler(); 93 } 94 void Run() 95 { 96 if (Status() == OSCL_REQUEST_ERR_NONE) 97 iContainer->TimerBaseElapsed(); 98 } 99 private: 100 CallbackTimerObserver *iContainer; 101}; 102 103 104template<class Alloc> 105class OsclTimer : public CallbackTimerObserver 106{ 107 public: 108 109 typedef CallbackTimer<Alloc> callback_timer_type; 110 111 /** 112 * Constructor 113 * 114 * @param frequency The frequency of the timer in cycles/second. A value of 115 * 1 means the timer will cycle in 1 second intervals. 116 */ 117 OsclTimer(const char *name, uint32 frequency = 1, int32 priority = OsclActiveObject::EPriorityNominal); 118 virtual ~OsclTimer(); 119 120 /** 121 * Set the global observer. Each timer can request a local 122 * observer, which if set overrides the global observer. 123 * 124 * @param obs observer object. 125 */ 126 void SetObserver(OsclTimerObserver *obs) 127 { 128 iObserver = obs; 129 } 130 /** 131 * Set the frequency of the timer in cycles/second. 132 * 133 * @param frequency A value of 1 means the timer will cycle in one second 134 * intervals, 1000 means millisecond intervals, etc. 135 */ 136 void SetFrequency(uint32 frequency); 137 138 /** 139 * Set the exact frequency of the timer in microsecond. 140 * 141 * @param frequency A value of 1 means the timer will cycle in one microsecond 142 * intervals, 1000 means millisecond intervals, etc. 143 */ 144 void SetExactFrequency(uint32 frequency); 145 146 /** 147 * Request a timer 148 * 149 * @param timerID used to identify the timer for cancellation. This value 150 * will be returned as part of the timeout event. 151 * @param timeoutInfo 152 * for user info. Returned to the observer on a timeout event 153 * @param cycles the number of cycles to wait before a timeout event. If 154 * the timer frequency is 1 and the cycles are set to 2, then 155 * the timeout event will occur in 2 seconds. 156 * @param obs a local observer object to be called on a timeout event. 157 * This observer overides the global observer if set. 158 */ 159 void Request(int32 timerID, int32 timeoutInfo, int32 cycles, OsclTimerObserver *obs = 0, bool recurring = 0); 160 /** 161 * Cancel a timer 162 * 163 * @param timerID used to identify the timer to cancel. 164 * @param timeoutInfo 165 * if not set to -1, this value will be used as additional 166 * matching criteria to cancel a timer. 167 */ 168 void Cancel(int32 timerID, int32 timeoutInfo = -1); 169 /** 170 * Cancel all pending timers. 171 */ 172 void Clear(); 173 174 private: 175 //Note: the timer needs to be a new'd object so that 176 //the CBase construction zeros the memory. 177 callback_timer_type *iTimer; 178 179 typedef struct _TimerEntry 180 { 181 int32 iCounter ; 182 int32 iTimerID ; 183 int32 iParam ; 184 OsclTimerObserver *iObserver; 185 bool iRecurring; 186 int32 iOrigCounter; 187 } TimerEntry; 188 189 typedef TimerEntry entry_type; 190 typedef Oscl_Vector<entry_type*, Alloc> entries_type; 191 typedef typename entries_type::iterator entries_type_iterator; 192 193 OsclTimerObserver *iObserver; 194 entries_type iEntries; 195 entries_type iEntriesWaitingToAdd; 196 entries_type iEntriesWaitingToCancel; 197 Oscl_TAlloc<entry_type, Alloc> iEntryAllocator; 198 199 bool iInCallback; 200 201 uint32 iCyclePeriod; 202 uint32 iTickCountPeriod; 203 uint32 iExpectedTimeout; 204 205 protected: 206 void TimerBaseElapsed(); 207 friend class CallbackTimer<Alloc>; 208}; 209 210template<class Alloc> 211OsclTimer<Alloc>::OsclTimer(const char *name, uint32 frequency, int32 priority) : 212 iObserver(0) 213 , iInCallback(false) 214 , iTickCountPeriod(0) 215 , iExpectedTimeout(0) 216{ 217 //use the allocator with placement 'new' 218 Alloc alloc; 219 iTimer = OSCL_PLACEMENT_NEW(alloc.ALLOCATE(sizeof(CallbackTimer<Alloc>)), CallbackTimer<Alloc>(*this, name, priority)); 220 SetFrequency(frequency); 221} 222 223template<class Alloc> 224OsclTimer<Alloc>::~OsclTimer() 225{ 226 // Make sure we're cancelled 227 if (iTimer) 228 iTimer->Cancel(); 229 if (iTimer) 230 { 231 iTimer->OSCL_TEMPLATED_DESTRUCTOR_CALL(callback_timer_type, CallbackTimer); 232 Alloc alloc; 233 alloc.deallocate(iTimer); 234 } 235 iTimer = NULL; 236 237 for (entries_type_iterator it = iEntries.begin(); it != iEntries.end(); it++) 238 { 239 iEntryAllocator.deallocate(*it); 240 } 241} 242 243template<class Alloc> 244void OsclTimer<Alloc>::SetFrequency(uint32 frequency) 245{ 246 // timer takes microseconds 247 iCyclePeriod = 1000000 / frequency; 248 // get tick count period 249 iTickCountPeriod = OsclTickCount::TickCountPeriod(); 250} 251 252template<class Alloc> 253void OsclTimer<Alloc>::SetExactFrequency(uint32 frequency) 254{ 255 // timer takes microseconds 256 iCyclePeriod = frequency; 257 // get tick count period 258 iTickCountPeriod = OsclTickCount::TickCountPeriod(); 259} 260 261// Request a timer 262template<class Alloc> 263void OsclTimer<Alloc>::Request(int32 timerID, int32 param, int32 cycles, OsclTimerObserver *obs, bool recurring) 264{ 265 266 // add to list of timers 267 entry_type *entry = iEntryAllocator.ALLOCATE(1); 268 entry->iTimerID = timerID; 269 entry->iParam = param; 270 entry->iCounter = cycles; 271 entry->iObserver = obs; 272 entry->iRecurring = recurring; 273 entry->iOrigCounter = entry->iCounter; 274 275 // if the request is called inside of a callback, then we must add it later 276 if (iInCallback) 277 { 278 iEntriesWaitingToAdd.push_back(entry); 279 return; 280 } 281 282 iEntries.push_back(entry); 283 284 if (iTimer) 285 { 286 iTimer->RunIfNotReady(iCyclePeriod); 287 } 288 289 if (iExpectedTimeout == 0) 290 { 291 iExpectedTimeout = (OsclTickCount::TickCount() * iTickCountPeriod) + iCyclePeriod; 292 } 293} 294 295// Cancel a timer 296template<class Alloc> 297void OsclTimer<Alloc>::Cancel(int32 timerID, int32 param) 298{ 299 300 if (iInCallback) 301 { 302 // add to list of timers 303 entry_type *entry = iEntryAllocator.ALLOCATE(1); 304 entry->iTimerID = timerID; 305 entry->iParam = param; 306 307 iEntriesWaitingToCancel.push_back(entry); 308 return; 309 } 310 311 // remove from list of timers 312 for (entries_type_iterator it = iEntries.begin(); it != iEntries.end(); it++) 313 { 314 if ((*it)->iTimerID == timerID) 315 { 316 // make sure the param matches unless it is not specified (-1) 317 if ((*it)->iParam == param || param == -1) 318 { 319 iEntryAllocator.deallocate(*it); 320 iEntries.erase(it); 321 return; 322 } 323 } 324 } 325} 326 327// Clear all waiting timers 328template<class Alloc> 329void OsclTimer<Alloc>::Clear() 330{ 331 for (entries_type_iterator it = iEntries.begin(); it != iEntries.end(); it++) 332 { 333 iEntryAllocator.deallocate(*it); 334 } 335 iEntries.clear(); 336} 337 338template<class Alloc> 339void OsclTimer<Alloc>::TimerBaseElapsed() 340{ 341 uint8 expiredFound = 0; 342 343 { 344 // call all whose timers have expired 345 for (entries_type_iterator it = iEntries.begin(); it != iEntries.end(); it++) 346 { 347 entry_type *entry = (*it); 348 if (--(entry->iCounter) <= 0) 349 { 350 if (!entry->iRecurring) expiredFound = 1; 351 if (entry->iRecurring) entry->iCounter = entry->iOrigCounter; 352 353 // use local observer if it exists, otherwise use global observer 354 OsclTimerObserver *obs = (entry->iObserver ? entry->iObserver : iObserver); 355 if (obs) 356 { 357 iInCallback = true; 358 obs->TimeoutOccurred(entry->iTimerID, entry->iParam); 359 iInCallback = false; 360 } 361 } 362 } 363 } 364 365 // remove from list all whose timers have expired 366 while (expiredFound) 367 { 368 expiredFound = 0; 369 for (entries_type_iterator it = iEntries.begin(); it != iEntries.end(); it++) 370 { 371 entry_type *entry = (*it); 372 if (entry->iCounter <= 0) 373 { 374 expiredFound = 1; 375 iEntryAllocator.deallocate(entry); 376 iEntries.erase(it); 377 break; 378 } 379 } 380 } 381 382 { 383 // if any timers were cancelled in the callback, process them now 384 for (entries_type_iterator it = iEntriesWaitingToCancel.begin(); it != iEntriesWaitingToCancel.end(); it++) 385 { 386 entry_type *entry = (*it); 387 Cancel(entry->iTimerID, entry->iParam); 388 iEntryAllocator.deallocate(entry); 389 } 390 iEntriesWaitingToCancel.clear(); 391 } 392 393 { 394 // if any timers were requested in the callback, process them now 395 for (entries_type_iterator it = iEntriesWaitingToAdd.begin(); it != iEntriesWaitingToAdd.end(); it++) 396 { 397 entry_type *entry = (*it); 398 Request(entry->iTimerID, entry->iParam, entry->iCounter, entry->iObserver); 399 iEntryAllocator.deallocate(entry); 400 } 401 iEntriesWaitingToAdd.clear(); 402 } 403 404 if (!iEntries.empty()) 405 { 406 // adjust for the jitter 407 uint32 time = OsclTickCount::TickCount() * iTickCountPeriod; 408 int32 jitter = time - iExpectedTimeout; 409 int32 waitperiod = iCyclePeriod - jitter; 410 411 // currently there is some problem on the phone if we send 412 // in real-time rather than with a slower (growing delay) H.223 mux output 413 // if jitter is too large in either direction, start over 414 if ((uint)OSCL_ABS(jitter) > iCyclePeriod) 415 { 416 iExpectedTimeout = time; 417 } 418 else 419 { 420 iExpectedTimeout += iCyclePeriod; 421 } 422 423 waitperiod = OSCL_MAX(waitperiod, 0); 424 425 if (iTimer) 426 { 427 iTimer->RunIfNotReady(waitperiod); 428 } 429 } 430 else 431 { 432 iExpectedTimeout = 0; 433 } 434} 435 436 437 438#endif 439