00001 // Copyright (c) 2000-2009 Nokia Corporation and/or its subsidiary(-ies). 00002 // All rights reserved. 00003 // This component and the accompanying materials are made available 00004 // under the terms of "Eclipse Public License v1.0" 00005 // which accompanies this distribution, and is available 00006 // at the URL "http://www.eclipse.org/legal/epl-v10.html". 00007 // 00008 // Initial Contributors: 00009 // Nokia Corporation - initial contribution. 00010 // 00011 // Contributors: 00012 // 00013 // Description: 00014 // Shows difference between CPeriodic and CHeartBeat 00015 // CPeriodic uses repeated RTimer::After() requests to get 00016 // a periodic tick - simple, but the time the tick is serviced lags 00017 // increasingly. 00018 // As a nuance of CPeriodic, it takes a TCallBack to service 00019 // its requests. 00020 // CHeartbeat uses repeated RTimer::Lock() requests: its 00021 // requests complete in synchronization with the beating 00022 // of the system clock. 00023 // As a nuance of CHeartbeat, it takes an MBeating* mixin: 00024 // the MBeating's Beat() function is called when completion 00025 // occurs in sync, and Synchronize() is called when 00026 // synchronization has been lost. 00027 // 00028 00029 00030 00031 // standard example header 00032 #include "CommonFramework.h" 00033 00034 // beginning of real example 00035 00036 #include <e32math.h> 00037 00038 void RandomDelay(TInt64& aSeed, TInt /*aTimerNumber*/) 00039 { 00040 // initialize seed first time through 00041 if (aSeed==0) 00042 { 00043 TTime time; 00044 time.HomeTime(); 00045 aSeed=time.Int64(); 00046 } 00047 // ok, here we go 00048 TReal randomZeroToOne; 00049 randomZeroToOne = Math::FRand(aSeed); 00050 TReal realDelay; 00051 realDelay = randomZeroToOne * randomZeroToOne * 2000000; 00052 TInt32 intDelay; 00053 Math::Int(intDelay, realDelay); 00054 TTimeIntervalMicroSeconds32 delayMicroSeconds; 00055 delayMicroSeconds=intDelay; 00056 User::After(delayMicroSeconds); 00057 } 00058 00059 // A version of the RandomDelay function which is not random ! 00060 // The delay is fixed at 1000000us and may be useful to 00061 // experiment with. 00062 // 00063 // 00064 //void RandomDelay(TInt64& /* aSeed */, TInt aTimerNumber) 00065 // { 00066 // User::After(1000000); 00067 // _LIT(KFormatMisc,"Delay for timer %d: 1000000us\n"); 00068 // console->Printf(KFormatMisc, aTimerNumber); 00069 // } 00070 00071 00072 class TAppRunner 00073 { 00074 public: 00075 TAppRunner(); 00076 void NotifyFinished(); // notify an active object has finished 00077 void NotifyStarted(); // notify an active object has started 00078 // private: 00079 TInt iActiveObjects; // count of active objects 00080 }; 00081 00082 TAppRunner::TAppRunner() 00083 { 00084 iActiveObjects=0; 00085 } 00086 00087 void TAppRunner::NotifyStarted() 00088 { 00089 iActiveObjects++; 00090 } 00091 00092 void TAppRunner::NotifyFinished() 00093 { 00094 iActiveObjects--; 00095 if (iActiveObjects==0) CActiveScheduler::Stop(); 00096 } 00097 00098 /* 00099 CPeriodicRunner class 00100 00101 Constructor makes a CPeriodic and sets it off with one-second ticks. 00102 These are fielded by the callback function, the static Tick(TAny*), 00103 which simply casts the pointer to a CPeriodicRunner* and calls 00104 the non-static callback, DoTick(). 00105 00106 Processing gets behind: when the ticks left have counted down to zero, 00107 it should be behind by a second or two. The destructor indicates how many 00108 seconds since the object's creation. 00109 */ 00110 00111 class CPeriodicRunner : public CBase 00112 { 00113 public: 00114 // construct, add CPeriodic to active scheduler, and start it 00115 static CPeriodicRunner* NewL(TInt aTickInterval, TInt aTotalTicks, TAppRunner& aAppRunner); 00116 ~CPeriodicRunner(); // destruct and give statistics 00117 protected: 00118 CPeriodicRunner(TInt aTickInterval, TInt aTotalTicks, TAppRunner& aAppRunner); 00119 private: 00120 void ConstructL(); // second construction phase 00121 // functions for TCallBack protocol 00122 static TInt Tick(TAny* aObject); // directly called 00123 void DoTick(); // indirectly called 00124 private: 00125 // constructor parameters 00126 TAppRunner& iAppRunner; // notify when started and finished 00127 TInt iTotalTicks; // total number of ticks requested 00128 TInt iTickInterval; // the tick interval in microseconds 00129 00130 // things set up by ConstructL() 00131 TTime iStartTime; // when we were started 00132 CPeriodic* iPeriodic; // periodic timer active object 00133 00134 // remaining ticks will be decremented as we go 00135 TInt iTicksLeft; // number of ticks before we expire 00136 TInt iTimerNumber; // indentifying number for the timer 00137 00138 // seed for random delay generator 00139 TInt64 iDelaySeed; 00140 }; 00141 00142 // protected C++ constructor 00143 CPeriodicRunner::CPeriodicRunner(TInt aTickInterval, TInt aTotalTicks, TAppRunner& aAppRunner) 00144 : iAppRunner(aAppRunner), iTotalTicks(aTotalTicks), iTickInterval(aTickInterval) 00145 {} 00146 00147 // private second-phase constructor 00148 void CPeriodicRunner::ConstructL() 00149 { 00150 iStartTime.HomeTime(); 00151 iPeriodic =CPeriodic::NewL(0); // neutral priority 00152 iAppRunner.NotifyStarted(); 00153 iTimerNumber = iAppRunner.iActiveObjects; // set idenfifying number for timer 00154 iTicksLeft = iTotalTicks; 00155 // variable (actually 1 second) delay and interval 00156 iPeriodic->Start(iTickInterval,iTickInterval,TCallBack(Tick, this)); 00157 } 00158 00159 // construct, add CPeriodic to active scheduler, and start it 00160 CPeriodicRunner* CPeriodicRunner::NewL(TInt aTickInterval, TInt aTotalTicks, TAppRunner& aAppRunner) 00161 { 00162 CPeriodicRunner* self=new (ELeave) CPeriodicRunner(aTickInterval, aTotalTicks, aAppRunner); 00163 CleanupStack::PushL(self); 00164 self->ConstructL(); 00165 CleanupStack::Pop(); 00166 return self; 00167 } 00168 00169 // destruct and give statistics 00170 CPeriodicRunner::~CPeriodicRunner() 00171 { 00172 TTimeIntervalMicroSeconds elapsedTime; 00173 TTime currentTime; 00174 // set current time 00175 currentTime.HomeTime(); // set currentTime to now 00176 // find and show elapsed time & ticks 00177 elapsedTime = currentTime.MicroSecondsFrom(iStartTime); 00178 00179 _LIT(KFormat1,"Periodic timer %d finished after: %Ld microseconds for %d %dus ticks\n"); 00180 console->Printf(KFormat1,iTimerNumber,elapsedTime.Int64(),iTotalTicks,iTickInterval); 00181 00182 00183 00184 // cancel any outstanding request; delete owned CPeriodic object 00185 iPeriodic->Cancel(); 00186 delete iPeriodic; 00187 // tell app runner we've finished (if we're last, scheduler will stop) 00188 iAppRunner.NotifyFinished(); 00189 } 00190 00191 // private 00192 TInt CPeriodicRunner::Tick(TAny* aObject) 00193 { 00194 ((CPeriodicRunner*)aObject)->DoTick(); // cast, and call non-static function 00195 return 1; 00196 } 00197 00198 // private 00199 void CPeriodicRunner::DoTick() 00200 { 00201 iTicksLeft--; 00202 _LIT(KFormat2,"Periodic timer %d: %d ticks done\n"); 00203 console->Printf(KFormat2, iTimerNumber, iTotalTicks - iTicksLeft); 00204 if(iTicksLeft==0) 00205 { 00206 delete this; 00207 } 00208 RandomDelay(iDelaySeed,iTimerNumber); // a random delay to mess up the timing 00209 } 00210 00211 /* 00212 CHeartbeatRunner class 00213 00214 This class receives beats in sync with the system clock. It also has a much 00215 nicer interface than for periodic timers - the MBeating mixin, which is nicely 00216 object-oriented. 00217 00218 Most of the time, the Beat() function is called which trivially updates the tick 00219 count. Occasionally, synchronization is lost, and the Synchronize() function 00220 is called instead: this must find out from the system time how many ticks should 00221 have been counted, and update things accordingly. 00222 00223 The destructor gives the same comparisons as the CPeriodic's. The discrepancy 00224 between the number of ticks and the number of seconds since construction should 00225 never be more than is accounted for by the last heartbeat. 00226 */ 00227 00228 class CHeartbeatRunner : public CBase, public MBeating 00229 { 00230 public: 00231 // construct, add CHeartbeat to active scheduler, and start it 00232 static CHeartbeatRunner* NewL(TInt aTickInterval, TInt aTotalTicks, TAppRunner& aAppRunner); 00233 ~CHeartbeatRunner(); // destruct and give statistics 00234 protected: 00235 CHeartbeatRunner(TInt aTickInterval, TInt aTotalTicks, TAppRunner& aAppRunner); 00236 private: 00237 void ConstructL(); 00238 // functions for MBeating protocol 00239 void Beat(); // called when beat works ok 00240 void Synchronize(); // called when we need to synchronize 00241 private: 00242 // constructor parameters 00243 TAppRunner& iAppRunner; // notify when started and finished 00244 TInt iTotalTicks; // number of ticks requested 00245 TInt iTickInterval; // tick length in microseconds 00246 // things set up by ConstructL 00247 TTime iStartTime; // when we were started 00248 CHeartbeat* iHeartbeat; // heartbeat active object 00249 // ticks left decrements as we go 00250 TInt iTicksLeft; // number of ticks before we expire 00251 TInt iTimerNumber; // indentifying number for the timer 00252 // seed for random delay generator 00253 TInt64 iDelaySeed; 00254 }; 00255 00256 // protected C++ constructor 00257 CHeartbeatRunner::CHeartbeatRunner(TInt aTickInterval, TInt aTotalTicks, TAppRunner& aAppRunner) 00258 :iAppRunner(aAppRunner), iTotalTicks(aTotalTicks), iTickInterval(aTickInterval) 00259 {} 00260 00261 // private second-phase constructor 00262 void CHeartbeatRunner::ConstructL() 00263 { 00264 iStartTime.HomeTime(); 00265 iHeartbeat=CHeartbeat::NewL(0); // neutral priority 00266 iAppRunner.NotifyStarted(); 00267 iTimerNumber = iAppRunner.iActiveObjects; // set idenfifying number for timer 00268 iTicksLeft = iTotalTicks; 00269 // start the heartbeat timer, beating exactly on the second 00270 iHeartbeat->Start(ETwelveOClock,this); 00271 } 00272 00273 // construct, add CHeartbeat to active scheduler, and start it 00274 CHeartbeatRunner* CHeartbeatRunner::NewL(TInt aTickInterval, TInt aTotalTicks, TAppRunner& aAppRunner) 00275 { 00276 CHeartbeatRunner* self=new (ELeave) CHeartbeatRunner(aTickInterval, aTotalTicks, aAppRunner); 00277 CleanupStack::PushL(self); 00278 self->ConstructL(); 00279 CleanupStack::Pop(); 00280 return self; 00281 } 00282 00283 // destruct and give statistics 00284 CHeartbeatRunner::~CHeartbeatRunner() 00285 { 00286 TTimeIntervalMicroSeconds elapsedTime; 00287 TTime currentTime; 00288 currentTime.HomeTime(); // set current time to now 00289 // find and show elapsed time & ticks 00290 elapsedTime = currentTime.MicroSecondsFrom(iStartTime); 00291 00292 _LIT(KFormat3,"Heartbeat timer %d finished after: %Ld microseonds for %d %dus ticks\n"); 00293 console->Printf(KFormat3,iTimerNumber,elapsedTime.Int64(),iTotalTicks,iTickInterval); 00294 00295 // cancel any outstanding request; delete owned CPeriodic object 00296 iHeartbeat->Cancel(); 00297 delete iHeartbeat; 00298 // tell app runner we've finished (if last, scheduler will stop) 00299 iAppRunner.NotifyFinished(); 00300 } 00301 00302 // private 00303 void CHeartbeatRunner::Beat() 00304 { 00305 iTicksLeft--; 00306 if(iTicksLeft<=0) 00307 delete this; 00308 else 00309 RandomDelay(iDelaySeed,iTimerNumber); // a random delay to mess up the timing 00310 } 00311 00312 // private 00313 void CHeartbeatRunner::Synchronize() 00314 { 00315 TInt ticksMissed = 0; 00316 // what time in microseconds should be for this tick 00317 TTime desiredTime = iStartTime + TTimeIntervalMicroSeconds((iTotalTicks - iTicksLeft) * iTickInterval); 00318 TTime currentTime; // set current time to now 00319 currentTime.HomeTime(); 00320 TTimeIntervalMicroSeconds missedTime = currentTime.MicroSecondsFrom(desiredTime); 00321 // Calculate the ticks missed (quickly!) 00322 TInt64 missedTimeInt = missedTime.Int64(); // convert the missed time interval to an Int64 00323 00324 ticksMissed = (missedTimeInt / iTickInterval); 00325 //ticksMissed = (missedTimeInt / iTickInterval).GetTInt(); 00326 00327 00328 // The following loop increments the ticks missed by the same amount, but takes much longer 00329 // while (desiredTime < currentTime) 00330 // { 00331 // desiredTime = desiredTime - TTimeIntervalMicroSeconds(iTickInterval); 00332 // ticksMissed++; 00333 // } 00334 _LIT(KFormat4,"Ticks done %d\n"); 00335 console->Printf(KFormat4, (iTotalTicks -iTicksLeft)); 00336 00337 iTicksLeft = iTicksLeft - ticksMissed; 00338 TTimeIntervalMicroSeconds elapsedTime; 00339 elapsedTime = currentTime.MicroSecondsFrom(iStartTime); // find and show elapsed time & ticks 00340 _LIT(KFormat5,"Elapsed time: %Ld microseconds\n"); 00341 console->Printf(KFormat5, elapsedTime.Int64()); 00342 00343 _LIT(KFormat6,"Synchronize heartbeat timer %d: ticks missed %d: left %d: done now %d\n"); 00344 console->Printf(KFormat6, 00345 iTimerNumber, 00346 ticksMissed, 00347 iTicksLeft, 00348 ((iTotalTicks - iTicksLeft) <= iTotalTicks) ? iTotalTicks - iTicksLeft : iTotalTicks 00349 ); 00350 // iTicksLeft can be less than zero 00351 if(iTicksLeft<=0) 00352 { 00353 delete this; 00354 } 00355 } 00356 00357 /* 00358 TAppRunner class 00359 00360 Encapsulates logic for stopping the active scheduler 00361 */ 00362 00363 00364 // do the example 00365 00366 void doExampleL() 00367 { 00368 // Make and install the active scheduler 00369 CActiveScheduler* scheduler = new (ELeave) CActiveScheduler; 00370 00371 // Push onto clean-up stack 00372 CleanupStack::PushL(scheduler); 00373 00374 // Install as active scheduler 00375 CActiveScheduler::Install(scheduler); 00376 00377 // Controls the stopping of the scheduler 00378 TAppRunner appRunner; 00379 00380 // Set the tick interval to 1 second. 00381 TInt TickInterval = 1000000; 00382 00383 // run each kind of timer for increasing numbers of ticks 00384 // was 10/40/10 00385 00386 for (TInt total_ticks=4; total_ticks<=6; total_ticks+=2) 00387 { 00388 // Create periodic timer 00389 // 00390 // [nb Comment next line out if you just want to see heart beat runner] 00391 CPeriodicRunner::NewL(TickInterval, total_ticks, appRunner); 00392 00393 // Create hearbeat 00394 // 00395 // [nb Comment next line out if you just want to see periodic timer] 00396 CHeartbeatRunner::NewL(TickInterval, total_ticks, appRunner); 00397 } 00398 00399 CActiveScheduler::Start(); 00400 CleanupStack::PopAndDestroy(); // scheduler 00401 } 00402
Copyright ©2010 Nokia Corporation and/or its subsidiary(-ies).
All rights
reserved. Unless otherwise stated, these materials are provided under the terms of the Eclipse Public License
v1.0.