kerneltest/e32test/timestamp/d_timestamp.cpp
branchRCL_3
changeset 43 c1f20ce4abcf
equal deleted inserted replaced
42:a179b74831c9 43:c1f20ce4abcf
       
     1 // Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of the License "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // d_timestamp.cpp
       
    15 //
       
    16 
       
    17 #include <kern_priv.h>
       
    18 #include <kernel.h>
       
    19 #include "d_timestamp.h"
       
    20 #include "d_timestamp_dev.h"
       
    21 
       
    22 // time stamp test defaults
       
    23 static const TInt KTimerDurationS = 5;  // time interval for NTimer
       
    24 static const TInt KNErrPercent = 1;  // percent error acceptable
       
    25 static const TInt KIterations = 5;  // required number of valid runs (with LPM entry) 
       
    26 static const TInt KRetries = 4;  // retries are reset on every succesful run
       
    27 
       
    28 //
       
    29 // DTimestampTestFactory
       
    30 //
       
    31 
       
    32 /**
       
    33    Standard export function for LDDs. This creates a DLogicalDevice derived object,
       
    34    in this case, our DTimestampTestFactory
       
    35 */
       
    36 DECLARE_STANDARD_LDD()
       
    37 	{
       
    38 	return new DTimestampTestFactory;
       
    39 	}
       
    40 
       
    41 /**
       
    42    Constructor
       
    43 */
       
    44 DTimestampTestFactory::DTimestampTestFactory()
       
    45 	{
       
    46 	// Set version number for this device
       
    47 	iVersion=RTimestampTest::VersionRequired();
       
    48     // Indicate that we work with a PDD
       
    49 	iParseMask=KDeviceAllowPhysicalDevice;
       
    50     }
       
    51 
       
    52 /**
       
    53    Second stage constructor for DTimestampTestFactory.
       
    54    This must at least set a name for the driver object.
       
    55 
       
    56    @return KErrNone if successful, otherwise one of the other system wide error codes.
       
    57 */
       
    58 TInt DTimestampTestFactory::Install()
       
    59 	{
       
    60 	return SetName(&RTimestampTest::Name());
       
    61 	}
       
    62 
       
    63 /**
       
    64    Destructor
       
    65 */
       
    66 DTimestampTestFactory::~DTimestampTestFactory()
       
    67 	{
       
    68     
       
    69     }
       
    70 
       
    71 /**
       
    72    Return the drivers capabilities.
       
    73    Called in the response to an RDevice::GetCaps() request.
       
    74 
       
    75    @param aDes User-side descriptor to write capabilities information into
       
    76 */
       
    77 void DTimestampTestFactory::GetCaps(TDes8& aDes) const
       
    78 	{
       
    79 	// Create a capabilities object
       
    80 	RTimestampTest::TCaps caps;
       
    81 	caps.iVersion = iVersion;
       
    82 	// Write it back to user memory
       
    83 	Kern::InfoCopy(aDes,(TUint8*)&caps,sizeof(caps));
       
    84 	}
       
    85 
       
    86 
       
    87 /**
       
    88    Called by the kernel's device driver framework to create a Logical Channel.
       
    89    This is called in the context of the user thread (client) which requested the creation of a Logical Channel
       
    90    (E.g. through a call to RBusLogicalChannel::DoCreate)
       
    91    The thread is in a critical section.
       
    92 
       
    93    @param aChannel Set to point to the created Logical Channel
       
    94 
       
    95    @return KErrNone if successful, otherwise one of the other system wide error codes.
       
    96 */
       
    97 TInt DTimestampTestFactory::Create(DLogicalChannelBase*& aChannel)
       
    98 	{
       
    99 	aChannel=new DTimestampTestChannel;
       
   100 	if(!aChannel)
       
   101         {
       
   102 		return KErrNoMemory;
       
   103         }
       
   104     
       
   105 	return KErrNone;
       
   106 	}
       
   107 
       
   108 
       
   109 //
       
   110 // Logical Channel
       
   111 //
       
   112 
       
   113 /**
       
   114    Constructor
       
   115 */
       
   116 DTimestampTestChannel::DTimestampTestChannel()
       
   117     :iTimer(timerExpire,this),iDfc(dfcFn,this,7),iStarted(EFalse)
       
   118 	{
       
   119 	// Get pointer to client threads DThread object
       
   120 	iClient=&Kern::CurrentThread();
       
   121 	// Open a reference on client thread so it's control block can't dissapear until
       
   122 	// this driver has finished with it.
       
   123 	// Note, this call to Open can't fail since its the thread we are currently running in
       
   124 	iClient->Open();
       
   125 	}
       
   126 
       
   127 /**
       
   128    Second stage constructor called by the kernel's device driver framework.
       
   129    This is called in the context of the user thread (client) which requested the creation of a Logical Channel
       
   130    (E.g. through a call to RBusLogicalChannel::DoCreate)
       
   131    The thread is in a critical section.
       
   132 
       
   133    @param aUnit The unit argument supplied by the client to RBusLogicalChannel::DoCreate
       
   134    @param aInfo The info argument supplied by the client to RBusLogicalChannel::DoCreate
       
   135    @param aVer The version argument supplied by the client to RBusLogicalChannel::DoCreate
       
   136 
       
   137    @return KErrNone if successful, otherwise one of the other system wide error codes.
       
   138 */
       
   139 TInt DTimestampTestChannel::DoCreate(TInt /*aUnit*/, const TDesC8* /*aInfo*/, const TVersion& aVer)
       
   140 	{
       
   141 	// Check version
       
   142 	if (!Kern::QueryVersionSupported(RTimestampTest::VersionRequired(),aVer))
       
   143 		return KErrNotSupported;
       
   144 
       
   145 	// Setup LDD for receiving client messages
       
   146     TInt r = Kern::CreateClientRequest(iStartRequest);
       
   147     if (r != KErrNone) return r;
       
   148     r = Kern::CreateClientDataRequest(iWaitOnTimerRequest);
       
   149     if (r != KErrNone) return r;
       
   150     r = Kern::DynamicDfcQCreate(iQue,Kern::DfcQue0()->iThread->iPriority,RTimestampTest::Name());
       
   151     if (KErrNone!=r) return r;
       
   152     iDfc.SetDfcQ(iQue);
       
   153     SetDfcQ(iQue);
       
   154     iMsgQ.Receive();
       
   155     // Done
       
   156 	return KErrNone;
       
   157 	}
       
   158 
       
   159 
       
   160 /**
       
   161    Destructor
       
   162 */
       
   163 DTimestampTestChannel::~DTimestampTestChannel()
       
   164 	{
       
   165 	// Cancel all processing that we may be doing
       
   166 	DoCancel(TUint(RTimestampTest::EAllRequests));
       
   167     Kern::DestroyClientRequest(iWaitOnTimerRequest);
       
   168     Kern::DestroyClientRequest(iStartRequest);
       
   169     iQue->Destroy();
       
   170 	// Close our reference on the client thread
       
   171 	Kern::SafeClose((DObject*&)iClient,NULL);
       
   172 	}
       
   173 
       
   174 /**
       
   175    Called when a user thread requests a handle to this channel.
       
   176 */
       
   177 TInt DTimestampTestChannel::RequestUserHandle(DThread* aThread, TOwnerType aType)
       
   178 	{
       
   179 	// Make sure that only our client can get a handle
       
   180 	if (aType!=EOwnerThread || aThread!=iClient)
       
   181 		return KErrAccessDenied;
       
   182 	return KErrNone;
       
   183 	}
       
   184 
       
   185 /**
       
   186    override SendMsg method to allow pinning data in the context of the client thread
       
   187 */
       
   188 TInt DTimestampTestChannel::SendMsg(TMessageBase* aMsg)
       
   189 	{
       
   190 	TThreadMessage& m=*(TThreadMessage*)aMsg;
       
   191     TInt id = m.iValue;
       
   192 
       
   193 	// we only support one client
       
   194 	if (id != (TInt)ECloseMsg && m.Client() != iClient)
       
   195 		return KErrAccessDenied;
       
   196 	
       
   197 	TInt r = KErrNone;
       
   198 	if (id != (TInt)ECloseMsg && id != KMaxTInt)
       
   199 		{
       
   200 		if (id<0)
       
   201 			{
       
   202 			TRequestStatus* pS=(TRequestStatus*)m.Ptr0();
       
   203 			r = SendRequest(aMsg);
       
   204 			if (r != KErrNone)
       
   205 				Kern::RequestComplete(pS,r);
       
   206 			}
       
   207 		else
       
   208 			r = SendControl(aMsg);
       
   209 		}
       
   210 	else
       
   211 		r = DLogicalChannel::SendMsg(aMsg);
       
   212 	
       
   213 	return r;
       
   214 	}
       
   215 
       
   216 /**
       
   217    Process a message for this logical channel.
       
   218    This function is called in the context of a DFC thread.
       
   219 
       
   220    @param aMessage The message to process.
       
   221    The iValue member of this distinguishes the message type:
       
   222    iValue==ECloseMsg, channel close message
       
   223    iValue==KMaxTInt, a 'DoCancel' message
       
   224    iValue>=0, a 'DoControl' message with function number equal to iValue
       
   225    iValue<0, a 'DoRequest' message with function number equal to ~iValue
       
   226 */
       
   227 void DTimestampTestChannel::HandleMsg(TMessageBase* aMsg)
       
   228 	{
       
   229 	TThreadMessage& m=*(TThreadMessage*)aMsg;
       
   230 
       
   231 	// Get message type
       
   232 	TInt id=m.iValue;
       
   233 
       
   234 	// Decode the message type and dispatch it to the relevent handler function...
       
   235 
       
   236 	if (id==(TInt)ECloseMsg)
       
   237 		{
       
   238 		// Channel Close
       
   239         DoCancel(TUint(RTimestampTest::EAllRequests));
       
   240         iMsgQ.CompleteAll(KErrServerTerminated);
       
   241 		m.Complete(KErrNone, EFalse);
       
   242 		return;
       
   243 		}
       
   244 
       
   245 	if (id==KMaxTInt)
       
   246 		{
       
   247 		// DoCancel
       
   248 		DoCancel(m.Int0());
       
   249 		m.Complete(KErrNone,ETrue);
       
   250 		return;
       
   251 		}
       
   252 
       
   253 	if (id<0)
       
   254 		{
       
   255 		// DoRequest
       
   256 		TRequestStatus* pS=(TRequestStatus*)m.Ptr0();
       
   257 		DoRequest(~id,pS,m.Ptr1(),m.Ptr2());
       
   258 		m.Complete(KErrNone,ETrue);
       
   259 		}
       
   260 	else
       
   261 		{
       
   262 		// DoControl
       
   263 		TInt r=DoControl(id,m.Ptr0(),m.Ptr1());
       
   264 		m.Complete(r,ETrue);
       
   265 		}
       
   266 	}
       
   267 
       
   268 /**
       
   269    Preprocess synchronous 'control' requests
       
   270 */
       
   271 TInt DTimestampTestChannel::SendControl(TMessageBase* aMsg)
       
   272 	{
       
   273 	TThreadMessage& m=*(TThreadMessage*)aMsg;
       
   274     TInt id=m.iValue;
       
   275 
       
   276 	switch (id)
       
   277 		{
       
   278         
       
   279     case RTimestampTest::EConfig:
       
   280         {
       
   281         STimestampTestConfig info;
       
   282 #ifdef __SMP__
       
   283         info.iFreq = NKern::TimestampFrequency();
       
   284 #else
       
   285         info.iFreq = NKern::FastCounterFrequency();
       
   286 #endif
       
   287         info.iIterations = KIterations;
       
   288         info.iRetries = KRetries;
       
   289         info.iTimerDurationS = KTimerDurationS;
       
   290         info.iErrorPercent = KNErrPercent;
       
   291         // Allow PDD to override defaults
       
   292         Pdd().TestConfig(info);
       
   293         kumemput(m.Ptr0(),&info,sizeof(STimestampTestConfig));
       
   294         return KErrNone;
       
   295 		}
       
   296     
       
   297         }
       
   298     
       
   299 
       
   300 	TInt r = DLogicalChannel::SendMsg(aMsg);
       
   301 	if (r != KErrNone)
       
   302 		return r;
       
   303 
       
   304 // 	switch (id)
       
   305 // 		{
       
   306 // 		}
       
   307 
       
   308 	return r;
       
   309 	}
       
   310 
       
   311 /**
       
   312    Process synchronous 'control' requests
       
   313 */
       
   314 TInt DTimestampTestChannel::DoControl(TInt aFunction, TAny* a1, TAny* a2)
       
   315 	{
       
   316 	(void)a2;   
       
   317 	(void)a1;   
       
   318 	(void) aFunction;
       
   319 
       
   320 	// TInt r = KErrNone;
       
   321 	// switch (aFunction)
       
   322 	// 	{
       
   323     // default:
       
   324     //     r = KErrNotSupported;
       
   325 	// 	}
       
   326 
       
   327 	return KErrNotSupported;
       
   328 	}
       
   329 
       
   330 
       
   331 /**
       
   332    Preprocess asynchronous requests.
       
   333 */
       
   334 TInt DTimestampTestChannel::SendRequest(TMessageBase* aMsg)
       
   335     {
       
   336 	TThreadMessage& m=*(TThreadMessage*)aMsg;
       
   337     TInt function = ~m.iValue;
       
   338     TRequestStatus* pS=(TRequestStatus*)m.Ptr0();
       
   339 		
       
   340 	TInt r = KErrNotSupported;
       
   341 
       
   342 	switch (function)
       
   343 		{
       
   344 		case RTimestampTest::EStart:
       
   345             if (!iStarted) 
       
   346                 {
       
   347                 r = iStartRequest->SetStatus(pS);
       
   348                 }
       
   349             else 
       
   350                 {
       
   351                 r = KErrInUse;
       
   352                 }
       
   353             break;
       
   354             
       
   355 		case RTimestampTest::EWaitOnTimer:
       
   356             if (iStarted)
       
   357                 {
       
   358                 iWaitOnTimerRequest->SetDestPtr(m.Ptr1());
       
   359                 r = iWaitOnTimerRequest->SetStatus(pS);
       
   360                 }
       
   361             else
       
   362                 {
       
   363                 r = KErrNotReady;
       
   364                 }
       
   365             
       
   366             break;
       
   367         default:
       
   368             r = KErrNotSupported;
       
   369 		}
       
   370 
       
   371 	if (r == KErrNone)
       
   372 		r = DLogicalChannel::SendMsg(aMsg);
       
   373 	return r;
       
   374     }
       
   375 
       
   376 
       
   377 /**
       
   378    Process asynchronous requests.
       
   379 */
       
   380 void DTimestampTestChannel::DoRequest(TInt aReqNo, TRequestStatus* aStatus, TAny* a1, TAny* a2)
       
   381 	{
       
   382 	(void)a2;   
       
   383 	(void)a1;   
       
   384     (void)aStatus;
       
   385     
       
   386 	TInt r = KErrNone;
       
   387 
       
   388 	switch(aReqNo)
       
   389 		{
       
   390     case RTimestampTest::EStart:
       
   391         iNTicks = (TInt) a1;
       
   392         r = iTimer.OneShot(0);
       
   393         if (KErrNone!=r) Kern::QueueRequestComplete(iClient,iStartRequest,r);
       
   394         break;
       
   395     case RTimestampTest::EWaitOnTimer:
       
   396         Pdd().StartLPMEntryCheck();   // PDD will start checking if we have entered LPM
       
   397         r = iTimer.Again(iNTicks);
       
   398         if (KErrNone!=r) Kern::QueueRequestComplete(iClient,iWaitOnTimerRequest,r);
       
   399         break;
       
   400 		}
       
   401     
       
   402 	}
       
   403 
       
   404 
       
   405 
       
   406 /**
       
   407    Process cancelling of asynchronous requests.
       
   408 */
       
   409 void DTimestampTestChannel::DoCancel(TUint aMask)
       
   410 	{
       
   411     (void)aMask;
       
   412     iTimer.Cancel(); // no real guarantees on SMP systems
       
   413     iDfc.Cancel();
       
   414 	}
       
   415 
       
   416 
       
   417 /**
       
   418  * process timer expiry
       
   419 */
       
   420 void DTimestampTestChannel::DoTimerExpire()
       
   421 	{
       
   422 #ifdef __SMP__
       
   423     TUint64 ts = NKern::Timestamp();
       
   424 #else
       
   425     TUint64 ts = NKern::FastCounter();
       
   426 #endif
       
   427     iTimestampDelta = ts-iLastTimestamp;
       
   428     iLastTimestamp = ts;
       
   429     iDfc.Add();
       
   430 	}
       
   431 
       
   432 void DTimestampTestChannel::timerExpire(TAny* aParam)
       
   433     {
       
   434     DTimestampTestChannel* pD = (DTimestampTestChannel*) aParam;
       
   435     pD->DoTimerExpire();
       
   436     }
       
   437 
       
   438 
       
   439 
       
   440 void DTimestampTestChannel::DoDfcFn()
       
   441 	{
       
   442     if (!iStarted)
       
   443         {
       
   444         iStarted = ETrue;
       
   445         Kern::QueueRequestComplete(iClient,iStartRequest,KErrNone);
       
   446         }
       
   447     else
       
   448         {
       
   449         iWaitOnTimerRequest->Data().iDelta = iTimestampDelta;
       
   450         // PDD will return ETrue here if we have entered LPM
       
   451         iWaitOnTimerRequest->Data().iLPMEntered = Pdd().EndLPMEntryCheck(); 
       
   452         Kern::QueueRequestComplete(iClient,iWaitOnTimerRequest,KErrNone);
       
   453         }
       
   454 	}
       
   455 
       
   456 void DTimestampTestChannel::dfcFn(TAny* aParam)
       
   457     {
       
   458     DTimestampTestChannel* pD = (DTimestampTestChannel*) aParam;
       
   459     pD->DoDfcFn();
       
   460     }
       
   461