sl@0: // Copyright (c) 1997-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\system\d_tick.cpp sl@0: // LDD for testing tick-based timers sl@0: // sl@0: // sl@0: sl@0: #include "platform.h" sl@0: #include sl@0: #if defined(__MEIG__) sl@0: #include sl@0: #elif defined(__MAWD__) sl@0: #include sl@0: #elif defined(__MISA__) sl@0: #include sl@0: #elif defined(__MCOT__) sl@0: #include sl@0: #elif defined(__MI920__) || defined(__NI1136__) sl@0: #include sl@0: #elif defined(__IS_OMAP1510__) || defined(__IS_OMAP1610__) sl@0: #include sl@0: #include sl@0: #elif defined(__WINS__) sl@0: #include "nk_priv.h" sl@0: #elif defined(__RVEMUBOARD__) sl@0: #include sl@0: #elif defined(__NE1_TB__) sl@0: #include sl@0: #endif sl@0: #include sl@0: #include "d_tick.h" sl@0: #include "../misc/prbs.h" sl@0: sl@0: #if defined(__WINS__) sl@0: typedef Int64 TCounter; sl@0: typedef Int64 TDelta; sl@0: #else sl@0: typedef TUint TCounter; sl@0: typedef TInt TDelta; sl@0: #endif sl@0: sl@0: #if defined(__MISA__)|| defined(__MCOT__) sl@0: inline TCounter TIMER() sl@0: { return *(volatile TUint*)KHwRwOstOscr; } sl@0: #endif sl@0: #if defined(__IS_OMAP1510__) || defined(__IS_OMAP1610__) sl@0: inline TCounter TIMER() sl@0: { return TOmapTimer::Timer3Value(); } sl@0: #endif sl@0: #ifdef __MAWD__ sl@0: inline TCounter TIMER() sl@0: { return *(volatile TUint*)(KWindBaseAddress+KWindTimer1Value16)&0xffff; } sl@0: #endif sl@0: #ifdef __MEIG__ sl@0: inline TCounter TIMER() sl@0: { return *(volatile TUint*)(KEigerBaseAddress+KEigerTimer1Data16)&0xffff; } sl@0: #endif sl@0: #if defined(__MI920__) || defined(__NI1136__) sl@0: inline TCounter TIMER() sl@0: { return *(volatile TUint*)(KHwCounterTimer1+KHoTimerValue)&0xffff;} sl@0: #endif sl@0: #if defined(__RVEMUBOARD__) sl@0: inline TCounter TIMER() sl@0: { return *(volatile TUint*)(KHwCounterTimer1+KHoTimerValue)&0xffff;} sl@0: #endif sl@0: #if defined(__NE1_TB__) sl@0: inline TCounter TIMER() sl@0: { return NETimer::Timer(2).iTimerCount; } sl@0: #endif sl@0: #if defined(__EPOC32__) && defined(__CPU_X86) sl@0: TCounter TIMER(); sl@0: void SetUpTimerChannel2(); sl@0: #endif sl@0: #ifdef __WINS__ sl@0: inline TCounter TIMER() sl@0: { sl@0: LARGE_INTEGER c; sl@0: QueryPerformanceCounter(&c); sl@0: return c.QuadPart; sl@0: } sl@0: #endif sl@0: sl@0: #if defined(__MISA__) || defined(__MCOT__) sl@0: inline TDelta TimeDelta(TCounter initial, TCounter final) sl@0: { return final-initial; } // SA1100 timer counts up sl@0: inline TInt LongTimeDelta(TCounter initial, TCounter final, TUint, TUint) sl@0: { return final-initial; } // SA1100 timer counts up sl@0: #endif sl@0: #if defined(__IS_OMAP1510__) || defined(__IS_OMAP1610__) sl@0: inline TDelta TimeDelta(TCounter initial, TCounter final) sl@0: { return initial-final; } // OMAP timer counts down sl@0: inline TInt LongTimeDelta(TCounter initial, TCounter final, TUint, TUint) sl@0: { return initial-final; } sl@0: #endif sl@0: #if defined(__MI920__) || defined(__NI1136__) sl@0: inline TDelta TimeDelta(TCounter initial, TCounter final) sl@0: { return (initial-final)&0xffff; } // Integrator timer counts down sl@0: TInt LongTimeDelta(TCounter initial, TCounter final, TUint init_ms, TUint final_ms) sl@0: { sl@0: TUint r=(initial-final)&0xffff; // Integrator timer counts down sl@0: TUint ms=final_ms-init_ms; sl@0: ms=2*ms-r; sl@0: ms=(ms+32768)&~0xffff; sl@0: return r+ms; sl@0: } sl@0: #endif sl@0: #if defined(__RVEMUBOARD__) sl@0: inline TDelta TimeDelta(TCounter initial, TCounter final) sl@0: { return (initial-final)&0xffff; } // Timer counts down sl@0: TInt LongTimeDelta(TCounter initial, TCounter final, TUint init_ms, TUint final_ms) sl@0: { sl@0: TUint r=(initial-final)&0xffff; // Timer counts down sl@0: TUint ms=final_ms-init_ms; sl@0: ms=2*ms-r; sl@0: ms=(ms+32768)&~0xffff; sl@0: return r+ms; sl@0: } sl@0: #endif sl@0: #if defined(__NE1_TB__) sl@0: inline TDelta TimeDelta(TCounter initial, TCounter final) sl@0: { return final - initial; } sl@0: inline TDelta LongTimeDelta(TCounter initial, TCounter final, TUint, TUint) sl@0: { return final - initial; } sl@0: #endif sl@0: #if defined(__MAWD__) || defined(__MEIG__) sl@0: inline TDelta TimeDelta(TCounter initial, TCounter final) sl@0: { return (initial-final)&0xffff; } // Eiger/Windermere timer counts down sl@0: TInt LongTimeDelta(TCounter initial, TCounter final, TUint init_ms, TUint final_ms) sl@0: { sl@0: TUint r=(initial-final)&0xffff; // Eiger/Windermere timer counts down sl@0: TUint ms=final_ms-init_ms; sl@0: ms=2*ms-r; sl@0: ms=(ms+32768)&~0xffff; sl@0: return r+ms; sl@0: } sl@0: #endif sl@0: #if defined(__EPOC32__) && defined(__CPU_X86) sl@0: TDelta TimeDelta(TUint initial, TUint final) sl@0: { sl@0: TUint tickdiff=(initial-final)&0xffff; sl@0: TUint msdiff=((final>>16)-(initial>>16))&0xffff; sl@0: msdiff=1193*msdiff-tickdiff; sl@0: msdiff=(msdiff+32768)&~0xffff; sl@0: return msdiff+tickdiff; sl@0: } sl@0: sl@0: TInt LongTimeDelta(TUint initial, TUint final, TUint init_ms, TUint final_ms) sl@0: { sl@0: TUint r=(initial-final)&0xffff; // PC timer counts down sl@0: TUint ms=final_ms-init_ms; sl@0: ms=1193*ms-r; sl@0: ms=(ms+32768)&~0xffff; sl@0: return r+ms; sl@0: } sl@0: #endif sl@0: #ifdef __WINS__ sl@0: inline TDelta TimeDelta(TCounter initial, TCounter final) sl@0: { return final-initial; } // counts up sl@0: inline TDelta LongTimeDelta(TCounter initial, TCounter final, TUint, TUint) sl@0: { return final-initial; } // counts up sl@0: #endif sl@0: sl@0: const TInt KMajorVersionNumber=0; sl@0: const TInt KMinorVersionNumber=1; sl@0: const TInt KBuildVersionNumber=1; sl@0: sl@0: const TInt KDaysFrom0ADTo2000AD=730497; // See US_TIME.CPP to verify this sl@0: const TInt KSecondsPerDay=86400; sl@0: sl@0: TUint TicksToMicroseconds(TDelta aTicks) sl@0: { sl@0: #if defined(__MISA__) || defined(__MCOT__) sl@0: Int64 ticks(aTicks); sl@0: ticks*=(1000000); sl@0: ticks+=KHwOscFreqHz/2; // 3.6864MHz tick sl@0: ticks/=KHwOscFreqHz; sl@0: return (TUint)ticks; sl@0: #endif sl@0: #if defined(__IS_OMAP1510__) || defined(__IS_OMAP1610__) sl@0: // Timer runs at 12Mhz/32 = 375kHz. Each tick is 2.66...us which is 16/6us sl@0: aTicks<<=4; // * 16 sl@0: aTicks+=3; // rounding to the closest number of us sl@0: return (TInt)(aTicks/6); // us = (ticks*16+3)/6 sl@0: #endif sl@0: #if defined(__MI920__) || defined(__NI1136__) sl@0: aTicks<<=14; // 1 tick = 32/3 us sl@0: aTicks+=768; // round sl@0: return (TInt)(aTicks/1536); sl@0: #endif sl@0: #if defined(__RVEMUBOARD__) sl@0: return (TInt)(aTicks*256); // 1 tick = 256 us sl@0: #endif sl@0: #if defined(__NE1_TB__) sl@0: NETimer& T2 = NETimer::Timer(2); sl@0: TUint prescale = __e32_find_ms1_32(T2.iPrescaler & 0x3f); sl@0: TUint f = 66666667 >> prescale; sl@0: TUint64 x = I64LIT(1000000); sl@0: x *= TUint64(aTicks); sl@0: x += TUint64(f>>1); sl@0: x /= TUint64(f); sl@0: return (TUint)x; sl@0: #endif sl@0: #if defined(__MAWD__) || defined(__MEIG__) sl@0: return aTicks*500; // 2kHz tick sl@0: #endif sl@0: #if defined(__EPOC32__) && defined(__CPU_X86) sl@0: return (aTicks*8381+4190)/10000; sl@0: #endif sl@0: #ifdef __WINS__ sl@0: LARGE_INTEGER f; sl@0: QueryPerformanceFrequency(&f); sl@0: aTicks*=1000000; sl@0: aTicks+=f.QuadPart/2; sl@0: aTicks/=f.QuadPart; sl@0: return (TUint)aTicks; sl@0: #endif sl@0: } sl@0: sl@0: class DTick; sl@0: class TTickTimer sl@0: { sl@0: public: sl@0: enum TMode sl@0: { sl@0: EOneShot, sl@0: EPeriodic, sl@0: EAbsolute, sl@0: ETickDelay, sl@0: }; sl@0: public: sl@0: TTickTimer(); sl@0: TInt Start(TInt aMode, TUint aMin, TUint aRange, TInt aCount); sl@0: void Cancel(); sl@0: void CompleteClient(TInt aValue); sl@0: static void TickCallBack(TAny* aPtr); sl@0: static void SecondCallBack(TAny* aPtr); sl@0: public: sl@0: TTickLink iTickLink; sl@0: TSecondLink iSecondLink; sl@0: TMode iMode; sl@0: TInt iInterval; sl@0: TTimeK iExpiryTime; sl@0: TUint iMin; sl@0: TUint iRange; sl@0: TInt iParam; sl@0: TCounter iStartTime0; sl@0: TUint iStartTime1; sl@0: TCounter iStartTime; sl@0: TInt iMinErr; sl@0: TInt iMaxErr; sl@0: Int64 iTotalErr; sl@0: TInt iCount; sl@0: TInt iRequestedCount; sl@0: TInt iIgnore; sl@0: DTick* iLdd; sl@0: TInt iId; sl@0: TClientRequest* iRequest; sl@0: }; sl@0: sl@0: class DTickFactory : public DLogicalDevice sl@0: // sl@0: // Tick timer LDD factory sl@0: // sl@0: { sl@0: public: sl@0: DTickFactory(); sl@0: virtual TInt Install(); //overriding pure virtual sl@0: virtual void GetCaps(TDes8& aDes) const; //overriding pure virtual sl@0: virtual TInt Create(DLogicalChannelBase*& aChannel); //overriding pure virtual sl@0: }; sl@0: sl@0: class DTick : public DLogicalChannelBase sl@0: // sl@0: // Tick timer LDD channel sl@0: // sl@0: { sl@0: public: sl@0: DTick(); sl@0: ~DTick(); sl@0: protected: sl@0: virtual TInt DoCreate(TInt aUnit, const TDesC8* anInfo, const TVersion& aVer); sl@0: virtual TInt Request(TInt aFunction, TAny* a1, TAny* a2); sl@0: public: sl@0: void TimerExpired(TInt anId); sl@0: inline DThread* Client() { return iThread; } sl@0: public: sl@0: DThread* iThread; sl@0: TInt iTickPeriodUs; sl@0: TTimeK iYear2000; sl@0: TTickTimer iTickTimer[KMaxTimers]; sl@0: TUint iSeed[2]; sl@0: }; sl@0: sl@0: TTickTimer::TTickTimer() sl@0: : iMode(EOneShot), sl@0: iInterval(0), sl@0: iExpiryTime(0), sl@0: iMin(0), sl@0: iRange(1), sl@0: iParam(0), sl@0: iStartTime0(0), sl@0: iStartTime1(0), sl@0: iStartTime(0), sl@0: iMinErr(KMaxTInt), sl@0: iMaxErr(KMinTInt), sl@0: iTotalErr(0), sl@0: iCount(0), sl@0: iRequestedCount(0), sl@0: iIgnore(0), sl@0: iLdd(NULL), sl@0: iId(0), sl@0: iRequest(NULL) sl@0: { sl@0: } sl@0: sl@0: void TTickTimer::TickCallBack(TAny* aPtr) sl@0: { sl@0: TCounter timer_val=TIMER(); sl@0: TTickTimer& m=*(TTickTimer*)aPtr; sl@0: TDelta time=TimeDelta(m.iStartTime, timer_val); sl@0: TInt time_us=TicksToMicroseconds(time); sl@0: TInt rounded_interval=((m.iInterval+500)/1000)*1000; sl@0: TInt error=time_us-rounded_interval; sl@0: if (!m.iIgnore) sl@0: { sl@0: if (errorm.iMaxErr) sl@0: m.iMaxErr=error; sl@0: m.iTotalErr+=error; sl@0: } sl@0: if (m.iIgnore==1 && m.iMode==EPeriodic) sl@0: { sl@0: m.iStartTime0=timer_val; sl@0: m.iStartTime1=NKern::TickCount(); sl@0: } sl@0: if ((m.iIgnore && m.iIgnore--) || (++m.iCountiSeed); sl@0: TUint ticks=(rnd%m.iRange)+m.iMin; sl@0: m.iInterval=ticks*m.iLdd->iTickPeriodUs; sl@0: m.iStartTime=TIMER(); sl@0: m.iTickLink.OneShot(m.iInterval, TickCallBack, &m); sl@0: } sl@0: else if (m.iMode==ETickDelay) sl@0: { sl@0: m.iStartTime=TIMER(); sl@0: m.iTickLink.OneShot(m.iInterval, TickCallBack, &m); sl@0: NKern::Sleep(m.iRange); sl@0: } sl@0: else sl@0: m.iStartTime=timer_val; sl@0: return; sl@0: } sl@0: m.CompleteClient(KErrNone); sl@0: if (m.iMode==EPeriodic) sl@0: { sl@0: m.iStartTime0=LongTimeDelta(m.iStartTime0, timer_val, m.iStartTime1, NKern::TickCount()); sl@0: m.iTickLink.Cancel(); sl@0: } sl@0: } sl@0: sl@0: void TTickTimer::SecondCallBack(TAny* aPtr) sl@0: { sl@0: TTickTimer& m=*(TTickTimer*)aPtr; sl@0: TTimeK now=Kern::SystemTime(); sl@0: Int64 error=now-m.iExpiryTime; sl@0: if (error>KMaxTInt) sl@0: error=KMaxTInt; sl@0: if (errorm.iMaxErr) sl@0: m.iMaxErr=(TInt)error; sl@0: m.iTotalErr+=error; sl@0: if (++m.iCountiSeed); sl@0: TUint secs=(rnd%m.iRange)+m.iMin; sl@0: m.iExpiryTime=now+secs*1000000+999999; sl@0: m.iExpiryTime/=1000000; sl@0: m.iExpiryTime*=1000000; sl@0: m.iSecondLink.At(m.iExpiryTime, SecondCallBack, &m); sl@0: return; sl@0: } sl@0: m.CompleteClient(KErrNone); sl@0: } sl@0: sl@0: TInt TTickTimer::Start(TInt aMode, TUint a1, TUint a2, TInt aCount) sl@0: { sl@0: TInt r=KErrGeneral; sl@0: iMode=(TMode)aMode; sl@0: iMin=a1; sl@0: iRange=a2; sl@0: iMinErr=KMaxTInt; sl@0: iMaxErr=KMinTInt; sl@0: iTotalErr=0; sl@0: iCount=0; sl@0: iRequestedCount=aCount; sl@0: switch (aMode) sl@0: { sl@0: case EOneShot: sl@0: { sl@0: TUint rnd=Random(iLdd->iSeed); sl@0: TUint ticks=(rnd%iRange)+iMin; sl@0: iInterval=ticks*iLdd->iTickPeriodUs; sl@0: iStartTime=TIMER(); sl@0: iStartTime0=0; sl@0: iStartTime1=0; sl@0: iTickLink.OneShot(iInterval, TickCallBack, this); sl@0: iIgnore=Min(aCount-1,1); sl@0: r=KErrNone; sl@0: break; sl@0: } sl@0: case EPeriodic: sl@0: { sl@0: iInterval=iMin*iLdd->iTickPeriodUs; sl@0: iStartTime=TIMER(); sl@0: iStartTime0=iStartTime; sl@0: iStartTime1=NKern::TickCount(); sl@0: iTickLink.Periodic(iInterval, TickCallBack, this); sl@0: iIgnore=Min(aCount-1,1); sl@0: r=KErrNone; sl@0: break; sl@0: } sl@0: case EAbsolute: sl@0: { sl@0: TUint rnd=Random(iLdd->iSeed); sl@0: TUint secs=(rnd%iRange)+iMin; sl@0: TTimeK now=Kern::SystemTime(); sl@0: iExpiryTime=now+secs*1000000+999999; sl@0: iExpiryTime/=1000000; sl@0: iExpiryTime*=1000000; sl@0: iSecondLink.At(iExpiryTime, SecondCallBack, this); sl@0: iIgnore=0; sl@0: iStartTime0=0; sl@0: iStartTime1=0; sl@0: r=KErrNone; sl@0: break; sl@0: } sl@0: case ETickDelay: sl@0: { sl@0: iInterval=iMin*iLdd->iTickPeriodUs; sl@0: iStartTime=TIMER(); sl@0: iStartTime0=0; sl@0: iStartTime1=0; sl@0: iTickLink.OneShot(iInterval, TickCallBack, this); sl@0: iIgnore=Min(aCount-1,1); sl@0: r=KErrNone; sl@0: break; sl@0: } sl@0: default: sl@0: break; sl@0: } sl@0: return r; sl@0: } sl@0: sl@0: void TTickTimer::CompleteClient(TInt aValue) sl@0: { sl@0: Kern::QueueRequestComplete(iLdd->Client(),iRequest,aValue); sl@0: } sl@0: sl@0: void TTickTimer::Cancel() sl@0: { sl@0: iTickLink.Cancel(); sl@0: iSecondLink.Cancel(); sl@0: CompleteClient(KErrCancel); sl@0: } sl@0: sl@0: DECLARE_STANDARD_LDD() sl@0: { sl@0: return new DTickFactory; sl@0: } sl@0: sl@0: DTickFactory::DTickFactory() sl@0: { sl@0: iVersion=TVersion(KMajorVersionNumber,KMinorVersionNumber,KBuildVersionNumber); sl@0: //iParseMask=0;//No units, no info, no PDD sl@0: //iUnitsMask=0;//Only one thing sl@0: } sl@0: sl@0: TInt DTickFactory::Create(DLogicalChannelBase*& aChannel) sl@0: // sl@0: // Create a new DTick on this logical device sl@0: // sl@0: { sl@0: aChannel=new DTick; sl@0: return aChannel?KErrNone:KErrNoMemory; sl@0: } sl@0: sl@0: TInt DTickFactory::Install() sl@0: // sl@0: // Install the LDD - overriding pure virtual sl@0: // sl@0: { sl@0: return SetName(&KTickTestLddName); sl@0: } sl@0: sl@0: void DTickFactory::GetCaps(TDes8& aDes) const sl@0: // sl@0: // Get capabilities - overriding pure virtual sl@0: // sl@0: { sl@0: TCapsTickTestV01 b; sl@0: b.iVersion=TVersion(KMajorVersionNumber,KMinorVersionNumber,KBuildVersionNumber); sl@0: Kern::InfoCopy(aDes,(TUint8*)&b,sizeof(b)); sl@0: } sl@0: sl@0: DTick::DTick() sl@0: // sl@0: // Constructor sl@0: // sl@0: { sl@0: TInt i; sl@0: for (i=0; iOpen(); sl@0: } sl@0: sl@0: TInt DTick::DoCreate(TInt /*aUnit*/, const TDesC8* /*anInfo*/, const TVersion& aVer) sl@0: // sl@0: // Create channel sl@0: // sl@0: { sl@0: sl@0: if (!Kern::QueryVersionSupported(TVersion(KMajorVersionNumber,KMinorVersionNumber,KBuildVersionNumber),aVer)) sl@0: return KErrNotSupported; sl@0: sl@0: for (TInt i=0; iSetStatus(info.iStatus); sl@0: if (r==KErrNone) sl@0: r=m.Start(info.iMode, info.iMin, info.iRange, info.iCount); sl@0: break; sl@0: } sl@0: case RTickTest::EControlStop: sl@0: { sl@0: m.Cancel(); sl@0: break; sl@0: } sl@0: case RTickTest::EControlGetInfo: sl@0: { sl@0: STickTestInfo info; sl@0: info.iMinErr=m.iMinErr; sl@0: info.iMaxErr=m.iMaxErr; sl@0: info.iCount=m.iCount; sl@0: info.iRequestedCount=m.iRequestedCount; sl@0: Int64 avg=m.iTotalErr/m.iCount; sl@0: info.iAvgErr=(TInt)avg; sl@0: info.iTotalTime=TicksToMicroseconds(m.iStartTime0); sl@0: kumemput(a2,&info,sizeof(info)); sl@0: break; sl@0: } sl@0: case RTickTest::EControlReadRtc: sl@0: { sl@0: TInt hwrtc; sl@0: Arch::TheAsic()->SystemTimeInSecondsFrom2000(hwrtc); sl@0: *(TTimeK*)a1=Kern::SystemTime(); sl@0: TTimeK hwtimeK=(TTimeK)hwrtc; sl@0: hwtimeK*=1000000; sl@0: hwtimeK+=iYear2000; sl@0: kumemput(a2,&hwtimeK,sizeof(hwtimeK)); sl@0: break; sl@0: } sl@0: case RTickTest::EControlGetTickPeriod: sl@0: { sl@0: r=iTickPeriodUs; sl@0: break; sl@0: } sl@0: default: sl@0: r=KErrNotSupported; sl@0: break; sl@0: } sl@0: NKern::ThreadLeaveCS(); sl@0: return r; sl@0: } sl@0: