diff -r f345bda72bc4 -r 43e37759235e Symbian3/Examples/guid-6013a680-57f9-415b-8851-c4fa63356636/_periodic_8cpp_source.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Symbian3/Examples/guid-6013a680-57f9-415b-8851-c4fa63356636/_periodic_8cpp_source.html Tue Mar 30 16:16:55 2010 +0100 @@ -0,0 +1,418 @@ + + +
+ +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 +