kerneltest/e32test/timestamp/d_timestamp.cpp
changeset 90 947f0dc9f7a8
child 148 31ea0f8e3c99
child 152 657f875b013e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kerneltest/e32test/timestamp/d_timestamp.cpp	Fri Apr 16 16:24:37 2010 +0300
@@ -0,0 +1,463 @@
+/*
+* Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: 
+*
+*/
+
+
+#include <kern_priv.h>
+#include <kernel.h>
+#include "d_timestamp.h"
+#include "d_timestamp_dev.h"
+
+// time stamp test defaults
+static const TInt KTimerDurationS = 5;  // time interval for NTimer
+static const TInt KNErrPercent = 1;  // percent error acceptable
+static const TInt KIterations = 5;  // required number of valid runs (with LPM entry) 
+static const TInt KRetries = 4;  // retries are reset on every succesful run
+
+//
+// DTimestampTestFactory
+//
+
+/**
+   Standard export function for LDDs. This creates a DLogicalDevice derived object,
+   in this case, our DTimestampTestFactory
+*/
+DECLARE_STANDARD_LDD()
+	{
+	return new DTimestampTestFactory;
+	}
+
+/**
+   Constructor
+*/
+DTimestampTestFactory::DTimestampTestFactory()
+	{
+	// Set version number for this device
+	iVersion=RTimestampTest::VersionRequired();
+    // Indicate that we work with a PDD
+	iParseMask=KDeviceAllowPhysicalDevice;
+    }
+
+/**
+   Second stage constructor for DTimestampTestFactory.
+   This must at least set a name for the driver object.
+
+   @return KErrNone if successful, otherwise one of the other system wide error codes.
+*/
+TInt DTimestampTestFactory::Install()
+	{
+	return SetName(&RTimestampTest::Name());
+	}
+
+/**
+   Destructor
+*/
+DTimestampTestFactory::~DTimestampTestFactory()
+	{
+    
+    }
+
+/**
+   Return the drivers capabilities.
+   Called in the response to an RDevice::GetCaps() request.
+
+   @param aDes User-side descriptor to write capabilities information into
+*/
+void DTimestampTestFactory::GetCaps(TDes8& aDes) const
+	{
+	// Create a capabilities object
+	RTimestampTest::TCaps caps;
+	caps.iVersion = iVersion;
+	// Write it back to user memory
+	Kern::InfoCopy(aDes,(TUint8*)&caps,sizeof(caps));
+	}
+
+
+/**
+   Called by the kernel's device driver framework to create a Logical Channel.
+   This is called in the context of the user thread (client) which requested the creation of a Logical Channel
+   (E.g. through a call to RBusLogicalChannel::DoCreate)
+   The thread is in a critical section.
+
+   @param aChannel Set to point to the created Logical Channel
+
+   @return KErrNone if successful, otherwise one of the other system wide error codes.
+*/
+TInt DTimestampTestFactory::Create(DLogicalChannelBase*& aChannel)
+	{
+	aChannel=new DTimestampTestChannel;
+	if(!aChannel)
+        {
+		return KErrNoMemory;
+        }
+    
+	return KErrNone;
+	}
+
+
+//
+// Logical Channel
+//
+
+/**
+   Constructor
+*/
+DTimestampTestChannel::DTimestampTestChannel()
+    :iTimer(timerExpire,this),iDfc(dfcFn,this,7),iStarted(EFalse)
+	{
+	// Get pointer to client threads DThread object
+	iClient=&Kern::CurrentThread();
+	// Open a reference on client thread so it's control block can't dissapear until
+	// this driver has finished with it.
+	// Note, this call to Open can't fail since its the thread we are currently running in
+	iClient->Open();
+	}
+
+/**
+   Second stage constructor called by the kernel's device driver framework.
+   This is called in the context of the user thread (client) which requested the creation of a Logical Channel
+   (E.g. through a call to RBusLogicalChannel::DoCreate)
+   The thread is in a critical section.
+
+   @param aUnit The unit argument supplied by the client to RBusLogicalChannel::DoCreate
+   @param aInfo The info argument supplied by the client to RBusLogicalChannel::DoCreate
+   @param aVer The version argument supplied by the client to RBusLogicalChannel::DoCreate
+
+   @return KErrNone if successful, otherwise one of the other system wide error codes.
+*/
+TInt DTimestampTestChannel::DoCreate(TInt /*aUnit*/, const TDesC8* /*aInfo*/, const TVersion& aVer)
+	{
+	// Check version
+	if (!Kern::QueryVersionSupported(RTimestampTest::VersionRequired(),aVer))
+		return KErrNotSupported;
+
+	// Setup LDD for receiving client messages
+    TInt r = Kern::CreateClientRequest(iStartRequest);
+    if (r != KErrNone) return r;
+    r = Kern::CreateClientDataRequest(iWaitOnTimerRequest);
+    if (r != KErrNone) return r;
+    r = Kern::DynamicDfcQCreate(iQue,Kern::DfcQue0()->iThread->iPriority,RTimestampTest::Name());
+    if (KErrNone!=r) return r;
+    iDfc.SetDfcQ(iQue);
+    SetDfcQ(iQue);
+    iMsgQ.Receive();
+    // Done
+	return KErrNone;
+	}
+
+
+/**
+   Destructor
+*/
+DTimestampTestChannel::~DTimestampTestChannel()
+	{
+	// Cancel all processing that we may be doing
+	DoCancel(TUint(RTimestampTest::EAllRequests));
+    Kern::DestroyClientRequest(iWaitOnTimerRequest);
+    Kern::DestroyClientRequest(iStartRequest);
+    iQue->Destroy();
+	// Close our reference on the client thread
+	Kern::SafeClose((DObject*&)iClient,NULL);
+	}
+
+/**
+   Called when a user thread requests a handle to this channel.
+*/
+TInt DTimestampTestChannel::RequestUserHandle(DThread* aThread, TOwnerType aType)
+	{
+	// Make sure that only our client can get a handle
+	if (aType!=EOwnerThread || aThread!=iClient)
+		return KErrAccessDenied;
+	return KErrNone;
+	}
+
+/**
+   override SendMsg method to allow pinning data in the context of the client thread
+*/
+TInt DTimestampTestChannel::SendMsg(TMessageBase* aMsg)
+	{
+	TThreadMessage& m=*(TThreadMessage*)aMsg;
+    TInt id = m.iValue;
+
+	// we only support one client
+	if (id != (TInt)ECloseMsg && m.Client() != iClient)
+		return KErrAccessDenied;
+	
+	TInt r = KErrNone;
+	if (id != (TInt)ECloseMsg && id != KMaxTInt)
+		{
+		if (id<0)
+			{
+			TRequestStatus* pS=(TRequestStatus*)m.Ptr0();
+			r = SendRequest(aMsg);
+			if (r != KErrNone)
+				Kern::RequestComplete(pS,r);
+			}
+		else
+			r = SendControl(aMsg);
+		}
+	else
+		r = DLogicalChannel::SendMsg(aMsg);
+	
+	return r;
+	}
+
+/**
+   Process a message for this logical channel.
+   This function is called in the context of a DFC thread.
+
+   @param aMessage The message to process.
+   The iValue member of this distinguishes the message type:
+   iValue==ECloseMsg, channel close message
+   iValue==KMaxTInt, a 'DoCancel' message
+   iValue>=0, a 'DoControl' message with function number equal to iValue
+   iValue<0, a 'DoRequest' message with function number equal to ~iValue
+*/
+void DTimestampTestChannel::HandleMsg(TMessageBase* aMsg)
+	{
+	TThreadMessage& m=*(TThreadMessage*)aMsg;
+
+	// Get message type
+	TInt id=m.iValue;
+
+	// Decode the message type and dispatch it to the relevent handler function...
+
+	if (id==(TInt)ECloseMsg)
+		{
+		// Channel Close
+        DoCancel(TUint(RTimestampTest::EAllRequests));
+        iMsgQ.CompleteAll(KErrServerTerminated);
+		m.Complete(KErrNone, EFalse);
+		return;
+		}
+
+	if (id==KMaxTInt)
+		{
+		// DoCancel
+		DoCancel(m.Int0());
+		m.Complete(KErrNone,ETrue);
+		return;
+		}
+
+	if (id<0)
+		{
+		// DoRequest
+		TRequestStatus* pS=(TRequestStatus*)m.Ptr0();
+		DoRequest(~id,pS,m.Ptr1(),m.Ptr2());
+		m.Complete(KErrNone,ETrue);
+		}
+	else
+		{
+		// DoControl
+		TInt r=DoControl(id,m.Ptr0(),m.Ptr1());
+		m.Complete(r,ETrue);
+		}
+	}
+
+/**
+   Preprocess synchronous 'control' requests
+*/
+TInt DTimestampTestChannel::SendControl(TMessageBase* aMsg)
+	{
+	TThreadMessage& m=*(TThreadMessage*)aMsg;
+    TInt id=m.iValue;
+
+	switch (id)
+		{
+        
+    case RTimestampTest::EConfig:
+        {
+        STimestampTestConfig info;
+#ifdef __SMP__
+        info.iFreq = NKern::TimestampFrequency();
+#else
+        info.iFreq = NKern::FastCounterFrequency();
+#endif
+        info.iIterations = KIterations;
+        info.iRetries = KRetries;
+        info.iTimerDurationS = KTimerDurationS;
+        info.iErrorPercent = KNErrPercent;
+        // Allow PDD to override defaults
+        Pdd().TestConfig(info);
+        kumemput(m.Ptr0(),&info,sizeof(STimestampTestConfig));
+        return KErrNone;
+		}
+    
+        }
+    
+
+	TInt r = DLogicalChannel::SendMsg(aMsg);
+	if (r != KErrNone)
+		return r;
+
+// 	switch (id)
+// 		{
+// 		}
+
+	return r;
+	}
+
+/**
+   Process synchronous 'control' requests
+*/
+TInt DTimestampTestChannel::DoControl(TInt aFunction, TAny* a1, TAny* a2)
+	{
+	(void)a2;   
+	(void)a1;   
+	(void) aFunction;
+
+	// TInt r = KErrNone;
+	// switch (aFunction)
+	// 	{
+    // default:
+    //     r = KErrNotSupported;
+	// 	}
+
+	return KErrNotSupported;
+	}
+
+
+/**
+   Preprocess asynchronous requests.
+*/
+TInt DTimestampTestChannel::SendRequest(TMessageBase* aMsg)
+    {
+	TThreadMessage& m=*(TThreadMessage*)aMsg;
+    TInt function = ~m.iValue;
+    TRequestStatus* pS=(TRequestStatus*)m.Ptr0();
+		
+	TInt r = KErrNotSupported;
+
+	switch (function)
+		{
+		case RTimestampTest::EStart:
+            if (!iStarted) 
+                {
+                r = iStartRequest->SetStatus(pS);
+                }
+            else 
+                {
+                r = KErrInUse;
+                }
+            break;
+            
+		case RTimestampTest::EWaitOnTimer:
+            if (iStarted)
+                {
+                iWaitOnTimerRequest->SetDestPtr(m.Ptr1());
+                r = iWaitOnTimerRequest->SetStatus(pS);
+                }
+            else
+                {
+                r = KErrNotReady;
+                }
+            
+            break;
+        default:
+            r = KErrNotSupported;
+		}
+
+	if (r == KErrNone)
+		r = DLogicalChannel::SendMsg(aMsg);
+	return r;
+    }
+
+
+/**
+   Process asynchronous requests.
+*/
+void DTimestampTestChannel::DoRequest(TInt aReqNo, TRequestStatus* aStatus, TAny* a1, TAny* a2)
+	{
+	(void)a2;   
+	(void)a1;   
+    (void)aStatus;
+    
+	TInt r = KErrNone;
+
+	switch(aReqNo)
+		{
+    case RTimestampTest::EStart:
+        iNTicks = (TInt) a1;
+        r = iTimer.OneShot(0);
+        if (KErrNone!=r) Kern::QueueRequestComplete(iClient,iStartRequest,r);
+        break;
+    case RTimestampTest::EWaitOnTimer:
+        Pdd().StartLPMEntryCheck();   // PDD will start checking if we have entered LPM
+        r = iTimer.Again(iNTicks);
+        if (KErrNone!=r) Kern::QueueRequestComplete(iClient,iWaitOnTimerRequest,r);
+        break;
+		}
+    
+	}
+
+
+
+/**
+   Process cancelling of asynchronous requests.
+*/
+void DTimestampTestChannel::DoCancel(TUint aMask)
+	{
+    (void)aMask;
+    iTimer.Cancel(); // no real guarantees on SMP systems
+    iDfc.Cancel();
+	}
+
+
+/**
+ * process timer expiry
+*/
+void DTimestampTestChannel::DoTimerExpire()
+	{
+#ifdef __SMP__
+    TUint64 ts = NKern::Timestamp();
+#else
+    TUint64 ts = NKern::FastCounter();
+#endif
+    iTimestampDelta = ts-iLastTimestamp;
+    iLastTimestamp = ts;
+    iDfc.Add();
+	}
+
+void DTimestampTestChannel::timerExpire(TAny* aParam)
+    {
+    DTimestampTestChannel* pD = (DTimestampTestChannel*) aParam;
+    pD->DoTimerExpire();
+    }
+
+
+
+void DTimestampTestChannel::DoDfcFn()
+	{
+    if (!iStarted)
+        {
+        iStarted = ETrue;
+        Kern::QueueRequestComplete(iClient,iStartRequest,KErrNone);
+        }
+    else
+        {
+        iWaitOnTimerRequest->Data().iDelta = iTimestampDelta;
+        // PDD will return ETrue here if we have entered LPM
+        iWaitOnTimerRequest->Data().iLPMEntered = Pdd().EndLPMEntryCheck(); 
+        Kern::QueueRequestComplete(iClient,iWaitOnTimerRequest,KErrNone);
+        }
+	}
+
+void DTimestampTestChannel::dfcFn(TAny* aParam)
+    {
+    DTimestampTestChannel* pD = (DTimestampTestChannel*) aParam;
+    pD->DoDfcFn();
+    }
+