sl@0: // Copyright (c) 1995-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of the License "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // e32test\active\t_cper.cpp sl@0: // Overview: sl@0: // Test periodic timers. sl@0: // API Information: sl@0: // CPeriodic, CHeartbeat sl@0: // Details: sl@0: // - Create some CPeriodic timer active objects with different priorities. sl@0: // - Start the periodic timers with varying delay time to start generation sl@0: // of first event and different intervals between events sl@0: // - Verify the callback functions associated with each periodic are called sl@0: // in order of the time when the event occurred and considering the priority sl@0: // of the periodics. sl@0: // - Create heartbeat timer with different priorities sl@0: // - Start one heartbeat synchronized at ETwelveOClock sl@0: // - Start two heartbeats synchronized at ETwelveOClock, ESixOClock sl@0: // - Start three heartbeats synchronized at ETwelveOClock, ESixOClock, ETwelveOClock sl@0: // - Display start time and beat time for each heartbeat timer sl@0: // - Check if the heap has been corrupted by all the tests. sl@0: // Platforms/Drives/Compatibility: sl@0: // All. sl@0: // Assumptions/Requirement/Pre-requisites: sl@0: // Failures and causes: sl@0: // - The first part of the test (for CPeriodic) will fail if the timers are not completed in order. sl@0: // The test on emulator is very sensitive on the background activities on PC. sl@0: // Base Port information: sl@0: // sl@0: // sl@0: sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: sl@0: LOCAL_D RTest test(_L("T_CPER")); sl@0: sl@0: class myScheduler: public CActiveScheduler sl@0: { sl@0: public: sl@0: virtual void Error(TInt anError) const; sl@0: }; sl@0: sl@0: void myScheduler::Error(TInt anError) const sl@0: // sl@0: // virtual error handler sl@0: // sl@0: { sl@0: test.Panic(anError,_L("myScheduler::Error")); sl@0: } sl@0: sl@0: TInt Array[11]; sl@0: TTime Times[11]; sl@0: TInt counter = 0; sl@0: sl@0: CPeriodic* pPer1; sl@0: CPeriodic* pPer2; sl@0: CPeriodic* pPer3; sl@0: CPeriodic* pPer4; sl@0: CPeriodic* pPer5; sl@0: CPeriodic* pPer6; sl@0: CPeriodic* pPer7; sl@0: sl@0: TInt CallBackFn(TAny* Ptr) sl@0: // sl@0: // Callback function used for all periodics sl@0: // On calling Ptr is actually a TInt - the periodic Id sl@0: // sl@0: { sl@0: if (counter < 11) sl@0: { sl@0: Array[counter] = (TInt)Ptr; sl@0: Times[counter].HomeTime(); sl@0: counter++; sl@0: } sl@0: return(0); sl@0: } sl@0: sl@0: TInt CallBackPanic(TAny* Ptr) sl@0: // sl@0: // Periodic should never get called sl@0: // sl@0: { sl@0: test.Printf(_L(" PERIODIC %d HAS GONE OFF!\n"),(TInt)Ptr); sl@0: test(EFalse); sl@0: return(KErrGeneral); sl@0: } sl@0: sl@0: class myTimer: public CTimer sl@0: { sl@0: public: sl@0: myTimer(TInt aPriority); sl@0: virtual void RunL(); sl@0: }; sl@0: sl@0: myTimer::myTimer(TInt aPriority) : CTimer(aPriority) sl@0: // sl@0: // Constructor - Creates AND ADDS TO MYSCHEDULER sl@0: // sl@0: { sl@0: ConstructL(); sl@0: myScheduler::Add(this); sl@0: } sl@0: sl@0: void myTimer::RunL() sl@0: // sl@0: // The timer stops the scheduler sl@0: // sl@0: { sl@0: myScheduler::Stop(); sl@0: test.Printf(_L(" Timer has stopped ActiveScheduler\n")); sl@0: } sl@0: sl@0: sl@0: // sl@0: // CHeartbeat test code sl@0: // sl@0: class CTick : public CBase, public MBeating sl@0: { sl@0: public: sl@0: virtual void Beat(); sl@0: virtual void Synchronize(); sl@0: void Display(); sl@0: TInt iTicks; sl@0: TTime iStartTime; sl@0: TTime iTimes[4]; sl@0: }; sl@0: void CTick::Beat() sl@0: { sl@0: sl@0: test.Printf(_L("Tick\n")); sl@0: iTimes[iTicks].HomeTime(); sl@0: if (++iTicks>=4) sl@0: CActiveScheduler::Stop(); sl@0: } sl@0: void CTick::Synchronize() sl@0: { sl@0: sl@0: test.Printf(_L("Sync tick to system clock\n")); sl@0: iStartTime.HomeTime(); sl@0: iTicks=0; sl@0: } sl@0: sl@0: void PrintTime(const TDesC& aName, const TTime& aTime) sl@0: { sl@0: TDateTime dt(aTime.DateTime()); sl@0: test.Printf(_L("%S = %02d:%02d:%02d:%06d\n"),&aName,dt.Hour(),dt.Minute(),dt.Second(),dt.MicroSecond()); sl@0: } sl@0: sl@0: void CTick::Display() sl@0: { sl@0: PrintTime(_L("Start time"),iStartTime); sl@0: TInt i; sl@0: for (i=0; i<4; i++) sl@0: { sl@0: TBuf<16> name; sl@0: name.Format(_L("Beat %d"),i); sl@0: PrintTime(name,iTimes[i]); sl@0: } sl@0: } sl@0: sl@0: class CTock : public CTick sl@0: { sl@0: public: sl@0: virtual void Beat(); sl@0: virtual void Synchronize(); sl@0: }; sl@0: sl@0: void CTock::Beat() sl@0: { sl@0: sl@0: iTimes[iTicks++].HomeTime(); sl@0: test.Printf(_L("Tock\n")); sl@0: } sl@0: sl@0: void CTock::Synchronize() sl@0: { sl@0: sl@0: test.Printf(_L("Sync tock to system clock\n")); sl@0: iStartTime.HomeTime(); sl@0: iTicks=0; sl@0: } sl@0: sl@0: class CBigTock : public CTick sl@0: { sl@0: public: sl@0: virtual void Beat(); sl@0: virtual void Synchronize(); sl@0: }; sl@0: sl@0: void CBigTock::Beat() sl@0: { sl@0: sl@0: iTimes[iTicks++].HomeTime(); sl@0: test.Printf(_L("TOCK!\n")); sl@0: } sl@0: sl@0: void CBigTock::Synchronize() sl@0: { sl@0: sl@0: test.Printf(_L("Sync TOCK to system clock\n")); sl@0: iStartTime.HomeTime(); sl@0: iTicks=0; sl@0: } sl@0: sl@0: void testHeartbeat() sl@0: // sl@0: // Test CHeartBeat sl@0: // sl@0: { sl@0: sl@0: test.Start(_L("Test CHeartbeat timer")); sl@0: CActiveScheduler *scheduler = new CActiveScheduler; sl@0: CActiveScheduler::Install(scheduler); sl@0: sl@0: test.Next(_L("Create a beating object synchronised at ETwelveOClock")); sl@0: CTick *tick=new CTick; sl@0: CHeartbeat *pH=NULL; sl@0: TRAPD(r, pH=CHeartbeat::NewL(EPriorityNormal)); sl@0: test(r==KErrNone); sl@0: test.Next(_L("Run for 4 beats on the second")); sl@0: pH->Start(ETwelveOClock, tick); sl@0: CActiveScheduler::Start(); sl@0: pH->Cancel(); sl@0: tick->Display(); sl@0: sl@0: User::After(1000000); sl@0: test.Next(_L("Create another heartbeat synchronised at ESixOClock")); sl@0: CHeartbeat *pH6=CHeartbeat::New(EPriorityNormal); sl@0: CTock *tock=new CTock; sl@0: test.Next(_L("Start both")); sl@0: pH->Start(ETwelveOClock, tick); sl@0: pH6->Start(ESixOClock, tock); sl@0: CActiveScheduler::Start(); sl@0: tick->Display(); sl@0: tock->Display(); sl@0: sl@0: pH->Cancel(); sl@0: pH6->Cancel(); sl@0: User::After(1000000); sl@0: test.Next(_L("Create another beating object synchronised at ESixOClock with a higher priority")); sl@0: CHeartbeat *pH2=CHeartbeat::New(EPriorityHigh); sl@0: CBigTock *bigtock=new CBigTock; sl@0: test.Next(_L("Start all")); sl@0: pH->Start(ETwelveOClock, tick); sl@0: pH6->Start(ESixOClock, tock); sl@0: pH2->Start(ESixOClock, bigtock); sl@0: CActiveScheduler::Start(); sl@0: pH->Cancel(); sl@0: pH2->Cancel(); sl@0: pH6->Cancel(); sl@0: tick->Display(); sl@0: tock->Display(); sl@0: bigtock->Display(); sl@0: sl@0: delete pH; sl@0: delete pH2; sl@0: delete pH6; sl@0: delete tock; sl@0: delete tick; sl@0: delete bigtock; sl@0: delete scheduler; sl@0: test.End(); sl@0: } sl@0: sl@0: void testLockSpec() sl@0: // sl@0: // test the operators defined for TTimerLockSpec sl@0: // sl@0: { sl@0: /* sl@0: test.Start(_L("Test pre fix operator ++")); sl@0: TTimerLockSpec i=ETwelveOClock,k=EOneOClock,l; sl@0: TInt j; sl@0: for (j=0; j<30; j++) sl@0: { sl@0: ++k=EOneOClock; sl@0: test(k==EOneOClock); sl@0: k=i; sl@0: l=++i; sl@0: switch (k) sl@0: { sl@0: case EOneOClock: sl@0: test(i==ETwoOClock); sl@0: test(l==ETwoOClock); sl@0: break; sl@0: case ETwoOClock: sl@0: test(i==EThreeOClock); sl@0: test(l==EThreeOClock); sl@0: break; sl@0: case EThreeOClock: sl@0: test(i==EFourOClock); sl@0: test(l==EFourOClock); sl@0: break; sl@0: case EFourOClock: sl@0: test(i==EFiveOClock); sl@0: test(l==EFiveOClock); sl@0: break; sl@0: case EFiveOClock: sl@0: test(i==ESixOClock); sl@0: test(l==ESixOClock); sl@0: break; sl@0: case ESixOClock: sl@0: test(i==ESevenOClock); sl@0: test(l==ESevenOClock); sl@0: break; sl@0: case ESevenOClock: sl@0: test(i==EEightOClock); sl@0: test(l==EEightOClock); sl@0: break; sl@0: case EEightOClock: sl@0: test(i==ENineOClock); sl@0: test(l==ENineOClock); sl@0: break; sl@0: case ENineOClock: sl@0: test(i==ETenOClock); sl@0: test(l==ETenOClock); sl@0: break; sl@0: case ETenOClock: sl@0: test(i==EElevenOClock); sl@0: test(l==EElevenOClock); sl@0: break; sl@0: case EElevenOClock: sl@0: test(i==ETwelveOClock); sl@0: test(l==ETwelveOClock); sl@0: break; sl@0: case ETwelveOClock: sl@0: test(i==EOneOClock); sl@0: test(l==EOneOClock); sl@0: break; sl@0: } sl@0: } sl@0: sl@0: test.Next(_L("Test post fix operator ++")); sl@0: for (j=0; j<30; j++) sl@0: { sl@0: ++k=EOneOClock; sl@0: test(k==EOneOClock); sl@0: k=i; sl@0: l=i++; sl@0: switch (k) sl@0: { sl@0: case EOneOClock: sl@0: test(i==ETwoOClock); sl@0: test(l==k); sl@0: break; sl@0: case ETwoOClock: sl@0: test(i==EThreeOClock); sl@0: test(l==k); sl@0: break; sl@0: case EThreeOClock: sl@0: test(i==EFourOClock); sl@0: test(l==k); sl@0: break; sl@0: case EFourOClock: sl@0: test(i==EFiveOClock); sl@0: test(l==k); sl@0: break; sl@0: case EFiveOClock: sl@0: test(i==ESixOClock); sl@0: test(l==k); sl@0: break; sl@0: case ESixOClock: sl@0: test(i==ESevenOClock); sl@0: test(l==k); sl@0: break; sl@0: case ESevenOClock: sl@0: test(i==EEightOClock); sl@0: test(l==k); sl@0: break; sl@0: case EEightOClock: sl@0: test(i==ENineOClock); sl@0: test(l==k); sl@0: break; sl@0: case ENineOClock: sl@0: test(i==ETenOClock); sl@0: test(l==k); sl@0: break; sl@0: case ETenOClock: sl@0: test(i==EElevenOClock); sl@0: test(l==k); sl@0: break; sl@0: case EElevenOClock: sl@0: test(i==ETwelveOClock); sl@0: test(l==k); sl@0: break; sl@0: case ETwelveOClock: sl@0: test(i==EOneOClock); sl@0: test(l==k); sl@0: break; sl@0: } sl@0: } sl@0: test.End(); sl@0: */ sl@0: } sl@0: sl@0: sl@0: GLDEF_C TInt E32Main() sl@0: { sl@0: sl@0: test.Title(); sl@0: __UHEAP_MARK; sl@0: test.Start(_L("Create some CPeriodics")); sl@0: sl@0: myScheduler* pScheduler = new myScheduler; sl@0: myScheduler::Install(pScheduler); sl@0: sl@0: pPer1 = CPeriodic::New(0); sl@0: pPer2 = CPeriodic::NewL(0); sl@0: pPer3 = CPeriodic::NewL(10); sl@0: pPer4 = CPeriodic::NewL(100); sl@0: pPer5 = CPeriodic::NewL(100); sl@0: pPer6 = CPeriodic::NewL(100); sl@0: pPer7 = CPeriodic::NewL(100); sl@0: myTimer* pTimer = new myTimer(50); sl@0: sl@0: test.Next(_L("Start them")); sl@0: sl@0: TCallBack callBack1(CallBackFn,(TAny*)1); sl@0: TCallBack callBack2(CallBackFn,(TAny*)2); sl@0: TCallBack callBack3(CallBackFn,(TAny*)3); sl@0: TCallBack callBack4(CallBackPanic,(TAny*)4); sl@0: TCallBack callBack5(CallBackPanic,(TAny*)5); sl@0: TCallBack callBack6(CallBackPanic,(TAny*)6); sl@0: TCallBack callBack7(CallBackPanic,(TAny*)7); sl@0: sl@0: TInt p=0; sl@0: HAL::Get(HAL::ESystemTickPeriod, p); sl@0: sl@0: User::After(p); // ensure tick does not occur while starting all these timers sl@0: sl@0: pPer1->Start(2*p+1,7*p+1,callBack1); //After 3 ticks, complete every 8th tick sl@0: pPer2->Start(1, 2*p+1,callBack2); //After 1 tick , complete every 3rd tick sl@0: pPer3->Start(7*p+1, p+1,callBack3); //After 8 ticks, complete every 2nd tick sl@0: sl@0: pPer4->Start(KMaxTInt,KMaxTInt,callBack4); sl@0: pPer5->Start(60000000,60000000,callBack5); sl@0: pPer6->Start(KMaxTInt/91,KMaxTInt/91,callBack6); sl@0: pPer7->Start(KMaxTInt/91+1,KMaxTInt/91+1,callBack7); sl@0: pTimer->After(20*p-1); // ensure there's enough time for them to fill up the array. sl@0: /* sl@0: Time per1 per2 per3 sl@0: 1 - sl@0: 2 sl@0: 3 - sl@0: 4 - sl@0: 5 sl@0: 6 sl@0: 7 - sl@0: 8 - sl@0: 9 sl@0: 10 - - sl@0: 11 - sl@0: 12 - sl@0: 13 - sl@0: 14 - sl@0: */ sl@0: sl@0: myScheduler::Start(); sl@0: sl@0: TInt i; sl@0: for (i=0; i(Times[i].Int64()-Times[0].Int64()),Array[i]); sl@0: } sl@0: sl@0: test(Array[0]==2); sl@0: test(Array[1]==1); sl@0: test(Array[2]==2); sl@0: test(Array[3]==2); sl@0: test(Array[4]==3); sl@0: TBool normal56 = (Array[5]==3 && Array[6]==2); sl@0: TBool reverse56 = (Array[5]==2 && Array[6]==3); sl@0: if (UserSvr::HalFunction(EHalGroupKernel, EKernelHalNumLogicalCpus, 0, 0) > 1) sl@0: { sl@0: // If there are multiple processors the order of 'simultaneous' timers is undefined since sl@0: // the test may get to run as soon as the first timer is completed, instead of only after sl@0: // the timer thread blocks, which would be after both timers completed. sl@0: test(normal56 || reverse56); sl@0: } sl@0: else sl@0: test(normal56); sl@0: test(Array[7]==1); sl@0: test(Array[8]==3); sl@0: test(Array[9]==2); sl@0: test(Array[10]==3); sl@0: sl@0: test.Next(_L("Destroy them")); sl@0: sl@0: delete pPer1; sl@0: delete pPer2; sl@0: delete pPer3; sl@0: delete pPer4; sl@0: delete pPer5; sl@0: delete pPer6; sl@0: delete pPer7; sl@0: delete pTimer; sl@0: delete pScheduler; sl@0: sl@0: test.Next(_L("Test CHeartbeat")); sl@0: testHeartbeat(); sl@0: test.Next(_L("Test TTimerLockSpec")); sl@0: testLockSpec(); sl@0: __UHEAP_MARKEND; sl@0: test.End(); sl@0: return(KErrNone); sl@0: }