kerneltest/e32test/iic/iic_psl/spi.cpp
changeset 0 a41df078684a
child 33 0173bcd7697c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/kerneltest/e32test/iic/iic_psl/spi.cpp	Mon Oct 19 15:55:17 2009 +0100
@@ -0,0 +1,1008 @@
+// Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
+// All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of the License "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:
+// e32test/iic/iic_psl/spi.cpp
+//
+#include "spi.h"
+
+#ifdef IIC_INSTRUMENTATION_MACRO
+#include <drivers/iic_trace.h>
+#endif
+
+#define NUM_CHANNELS 4 // Arbitrary
+
+// Macros to be updated(?) with interaction with Configuration Repository
+const TInt KChannelTypeArray[NUM_CHANNELS] = {DIicBusChannel::EMaster, DIicBusChannel::EMaster, DIicBusChannel::ESlave, DIicBusChannel::EMaster};
+#define CHANNEL_TYPE(n) (KChannelTypeArray[n])	
+const DIicBusChannel::TChannelDuplex KChannelDuplexArray[NUM_CHANNELS] = {DIicBusChannel::EHalfDuplex, DIicBusChannel::EHalfDuplex, DIicBusChannel::EHalfDuplex, DIicBusChannel::EFullDuplex};
+#define CHANNEL_DUPLEX(n) (KChannelDuplexArray[n]) 
+
+#ifdef LOG_SPI
+#define SPI_PRINT(str) Kern::Printf str
+#else
+#define SPI_PRINT(str)
+#endif
+
+_LIT(KSpiThreadName,"SpiChannelThread");
+
+const TInt KSpiThreadPriority = 5; // Arbitrary, can be 0-7, 7 highest
+
+#ifdef STANDALONE_CHANNEL
+_LIT(KPddNameSpi,"spi_ctrless.pdd");
+#else
+_LIT(KPddNameSpi,"spi.pdd");
+#endif
+
+#ifndef STANDALONE_CHANNEL
+LOCAL_C TInt8 AssignChanNum()
+	{
+	static TInt8 iBaseChanNum = KSpiChannelNumBase;
+	SPI_PRINT(("SPI AssignChanNum - on entry, iBaseCanNum = 0x%x\n",iBaseChanNum));
+	return iBaseChanNum++; // Arbitrary, for illustration
+	}
+#endif
+
+NONSHARABLE_CLASS(DSimulatedSpiDevice) : public DPhysicalDevice
+	{
+// Class to faciliate loading of the IIC classes
+public:
+	class TCaps
+		{
+	public:
+		TVersion iVersion;
+		};
+public:
+	DSimulatedSpiDevice();
+	virtual TInt Install();
+	virtual TInt Create(DBase*& aChannel, TInt aUnit, const TDesC8* anInfo, const TVersion& aVer);
+	virtual TInt Validate(TInt aUnit, const TDesC8* anInfo, const TVersion& aVer);
+	virtual void GetCaps(TDes8& aDes) const;
+	inline static TVersion VersionRequired();
+	};
+
+TVersion DSimulatedSpiDevice::VersionRequired()
+	{
+	SPI_PRINT(("DSimulatedSpiDevice::VersionRequired\n"));
+	return TVersion(KIicClientMajorVersionNumber,KIicClientMinorVersionNumber,KIicClientBuildVersionNumber);
+	}
+
+/** Factory class constructor */
+DSimulatedSpiDevice::DSimulatedSpiDevice()
+	{
+	SPI_PRINT(("DSimulatedSpiDevice::DSimulatedSpiDevice\n"));
+    iVersion = DSimulatedSpiDevice::VersionRequired();
+	}
+
+TInt DSimulatedSpiDevice::Install()
+    {
+	SPI_PRINT(("DSimulatedSpiDevice::Install\n"));
+    return(SetName(&KPddNameSpi));
+    }
+
+/**  Called by the kernel's device driver framework to create a Physical Channel. */
+TInt DSimulatedSpiDevice::Create(DBase*& /*aChannel*/, TInt /*aUint*/, const TDesC8* /*anInfo*/, const TVersion& /*aVer*/)
+    {
+	SPI_PRINT(("DSimulatedSpiDevice::Create\n"));
+    return KErrNone;
+    }
+
+/**  Called by the kernel's device driver framework to check if this PDD is suitable for use with a Logical Channel.*/
+TInt DSimulatedSpiDevice::Validate(TInt /*aUnit*/, const TDesC8* /*anInfo*/, const TVersion& aVer)
+    {
+	SPI_PRINT(("DSimulatedSpiDevice::Validate\n"));
+   	if (!Kern::QueryVersionSupported(DSimulatedSpiDevice::VersionRequired(),aVer))
+		return(KErrNotSupported);
+    return KErrNone;
+    }
+
+/** Return the driver capabilities */
+void DSimulatedSpiDevice::GetCaps(TDes8& aDes) const
+    {
+	SPI_PRINT(("DSimulatedSpiDevice::GetCaps\n"));
+	// Create a capabilities object
+	TCaps caps;
+	caps.iVersion = iVersion;
+	// Zero the buffer
+	TInt maxLen = aDes.MaxLength();
+	aDes.FillZ(maxLen);
+	// Copy capabilities
+	TInt size=sizeof(caps);
+	if(size>maxLen)
+	   size=maxLen;
+	aDes.Copy((TUint8*)&caps,size);
+    }
+
+
+DSimulatedSpiDevice* gDummyDevice;
+
+// supported channels for this implementation
+static DIicBusChannel* ChannelPtrArray[NUM_CHANNELS];
+
+
+//DECLARE_EXTENSION_WITH_PRIORITY(BUS_IMPLMENTATION_PRIORITY)	
+DECLARE_STANDARD_PDD()		// SPI test driver to be explicitly loaded as an LDD, not kernel extension
+	{
+	if(gDummyDevice == NULL)
+		gDummyDevice = new DSimulatedSpiDevice;
+	if(gDummyDevice == NULL)
+		return NULL;
+	SPI_PRINT(("\n\nSPI PDD, channel creation loop follows ...\n"));
+
+#ifndef STANDALONE_CHANNEL
+	DIicBusChannel* chan=NULL;
+	for(TInt i=0; i<NUM_CHANNELS; i++)
+		{
+	SPI_PRINT(("\n"));
+		if(CHANNEL_TYPE(i) == (DIicBusChannel::EMaster))
+			{
+			chan=new DSimulatedIicBusChannelMasterSpi(BUS_TYPE,CHANNEL_DUPLEX(i));
+			if(!chan)
+				return NULL;
+			SPI_PRINT(("SPI chan created at 0x%x\n",chan));
+			if(((DSimulatedIicBusChannelMasterSpi*)chan)->Create()!=KErrNone)
+				return NULL;
+			}
+		else if(CHANNEL_TYPE(i) == DIicBusChannel::EMasterSlave)
+			{
+			DIicBusChannel* chanM=new DSimulatedIicBusChannelMasterSpi(BUS_TYPE,CHANNEL_DUPLEX(i));
+			if(!chanM)
+				return NULL;
+			DIicBusChannel* chanS=new DSimulatedIicBusChannelSlaveSpi(BUS_TYPE,CHANNEL_DUPLEX(i));
+			if(!chanS)
+				return NULL;
+			// For MasterSlave channel, the channel number for both the Master and Slave channels must be the same
+			TInt8 msChanNum = ((DSimulatedIicBusChannelMasterSpi*)chanM)->GetChanNum();
+			((DSimulatedIicBusChannelSlaveSpi*)chanS)->SetChanNum(msChanNum);
+
+			chan=new DIicBusChannelMasterSlave(BUS_TYPE,CHANNEL_DUPLEX(i),(DIicBusChannelMaster*)chanM,(DIicBusChannelSlave*)chanS); // Generic implementation
+			if(!chan)
+				return NULL;
+			SPI_PRINT(("SPI chan created at 0x%x\n",chan));
+			if(((DIicBusChannelMasterSlave*)chan)->DoCreate()!=KErrNone)
+				return NULL;
+			}
+		else
+			{
+			chan=new DSimulatedIicBusChannelSlaveSpi(BUS_TYPE,CHANNEL_DUPLEX(i));
+			if(!chan)
+				return NULL;
+			SPI_PRINT(("SPI chan created at 0x%x\n",chan));
+			if(((DSimulatedIicBusChannelSlaveSpi*)chan)->Create()!=KErrNone)
+				return NULL;
+			}
+		ChannelPtrArray[i]=chan;
+		}
+	SPI_PRINT(("\nSPI PDD, channel creation loop done- about to invoke RegisterChannels\n\n"));
+#ifdef IIC_INSTRUMENTATION_MACRO
+	IIC_REGISTERCHANS_START_PSL_TRACE;
+#endif
+
+	TInt r = KErrNone;
+	r=DIicBusController::RegisterChannels(ChannelPtrArray,NUM_CHANNELS);
+
+#ifdef IIC_INSTRUMENTATION_MACRO
+	IIC_REGISTERCHANS_END_PSL_TRACE;
+#endif
+	SPI_PRINT(("\nSPI - returned from RegisterChannels with r=%d\n",r));
+	if(r!=KErrNone)
+		{
+		delete chan;
+		return NULL;
+		}
+#endif
+	return gDummyDevice;
+	}
+
+#ifdef STANDALONE_CHANNEL
+EXPORT_C
+#endif
+	DSimulatedIicBusChannelMasterSpi::DSimulatedIicBusChannelMasterSpi(const TBusType aBusType, const TChannelDuplex aChanDuplex)
+	: DIicBusChannelMaster(aBusType,aChanDuplex)
+	{
+	SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::DSimulatedIicBusChannelMasterSpi, aBusType=%d,aChanDuplex=%d\n",aBusType,aChanDuplex));
+#ifndef STANDALONE_CHANNEL
+	iChannelNumber = AssignChanNum();
+#endif
+	SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::DSimulatedIicBusChannelMasterSpi, iChannelNumber=%d\n",iChannelNumber));
+	iTestState = ETestNone;
+	iChannelState = EIdle;
+	}
+
+// The time-out call back invoked when the Slave exeecds the allowed response time
+TInt DSimulatedIicBusChannelMasterSpi::HandleSlaveTimeout()
+	{
+	SPI_PRINT(("HandleSlaveTimeout \n"));
+	return AsynchStateMachine(ETimeExpired); 
+	}
+
+TInt DSimulatedIicBusChannelMasterSpi::DoCreate()
+	{
+	SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::DoCreate\n"));
+	TInt r=Init();	// PIL Base class initialisation
+	r=Kern::DynamicDfcQCreate(iDynamicDfcQ,KSpiThreadPriority,KSpiThreadName);
+	if(r == KErrNone)
+		SetDfcQ((TDfcQue*)iDynamicDfcQ);
+	DSimulatedIicBusChannelMasterSpi::SetRequestDelayed(this,EFalse);
+	return r;
+	}
+
+TInt DSimulatedIicBusChannelMasterSpi::CheckHdr(TDes8* aHdr)
+	{
+	SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::CheckHdr\n"));
+
+	TConfigSpiBufV01* spiBuf = (TConfigSpiBufV01*)aHdr;
+	TConfigSpiV01* spiPtr = &((*spiBuf)());
+
+	// Valid values for the device ID will depend on the bus configuration
+	//
+	// Check that the values for word width, clock speed and clock mode are recognised
+	if((spiPtr->iWordWidth < 0) || (spiPtr->iWordWidth > ESpiWordWidth_16))
+		{
+		SPI_PRINT(("ERROR: DSimulatedIicBusChannelMasterSpi::CheckHdr unrecognised word width identifier %d\n",spiPtr->iWordWidth));
+		return KErrArgument;
+		}
+	if(spiPtr->iClkSpeedHz < 0)
+		{
+		SPI_PRINT(("ERROR: DSimulatedIicBusChannelMasterSpi::CheckHdr negative clock speed specified %d\n",spiPtr->iClkSpeedHz));
+		return KErrArgument;
+		}
+	if((spiPtr->iClkMode < 0) || (spiPtr->iClkMode > ESpiPolarityHighRisingEdge))
+		{
+		SPI_PRINT(("ERROR: DSimulatedIicBusChannelMasterSpi::CheckHdr unrecognised clock mode identifier %d\n",spiPtr->iClkMode));
+		return KErrArgument;
+		}
+	// Values for the timeout period are arbitrary - can only check it is not a negative value
+	if(spiPtr->iTimeoutPeriod < 0)
+		{
+		SPI_PRINT(("ERROR: DSimulatedIicBusChannelMasterSpi::CheckHdr negative timeout period %d\n",spiPtr->iTimeoutPeriod));
+		return KErrArgument;
+		}
+	if((spiPtr->iEndianness < 0) || (spiPtr->iEndianness > ELittleEndian))
+		{
+		SPI_PRINT(("ERROR: DSimulatedIicBusChannelMasterSpi::CheckHdr unrecognised endianness identifier %d\n",spiPtr->iEndianness));
+		return KErrArgument;
+		}
+	if((spiPtr->iBitOrder < 0) || (spiPtr->iBitOrder > EMsbFirst))
+		{
+		SPI_PRINT(("ERROR: DSimulatedIicBusChannelMasterSpi::CheckHdr unrecognised bit order identifier %d\n",spiPtr->iBitOrder));
+		return KErrArgument;
+		}
+	if((spiPtr->iSSPinActiveMode < 0) || (spiPtr->iSSPinActiveMode > ESpiCSPinActiveHigh))
+		{
+		SPI_PRINT(("ERROR: DSimulatedIicBusChannelMasterSpi::CheckHdr unrecognised Slave select pin mode identifier %d\n",spiPtr->iSSPinActiveMode));
+		return KErrArgument;
+		}
+	SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::CheckHdr word width = %d\n",spiPtr->iWordWidth));
+	SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::CheckHdr clock speed = %d\n",spiPtr->iClkSpeedHz));
+	SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::CheckHdr clock mode = %d\n",spiPtr->iClkMode));
+	SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::CheckHdr timeout period = %d\n",spiPtr->iTimeoutPeriod));
+	SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::CheckHdr endianness = %d\n",spiPtr->iEndianness));
+	SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::CheckHdr bit order = %d\n",spiPtr->iBitOrder));
+	SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::CheckHdr transaction wait cycles = %d\n",spiPtr->iTransactionWaitCycles));
+	SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::CheckHdr slave select pin mode = %d\n",spiPtr->iSSPinActiveMode));
+
+	// For the set of tests expecft the following values
+	// ESpiWordWidth_8, 100kHz, ESpiPolarityLowRisingEdge,aTimeoutPeriod=100
+	// EBigEndian, EMsbFirst, 10 wait cycles, Slave select active low
+	if(	(spiPtr->iWordWidth != ESpiWordWidth_8)	||
+		(spiPtr->iClkSpeedHz != 100000)	||
+		(spiPtr->iClkMode != ESpiPolarityLowRisingEdge)	||
+		(spiPtr->iTimeoutPeriod != 100) ||
+		(spiPtr->iEndianness != ELittleEndian) ||
+		(spiPtr->iBitOrder != EMsbFirst) ||
+		(spiPtr->iTransactionWaitCycles != 10) ||
+		(spiPtr->iSSPinActiveMode != ESpiCSPinActiveLow) )
+		return KErrCorrupt;
+	return KErrNone;
+	}
+
+TInt DSimulatedIicBusChannelMasterSpi::CompareTransactionOne(TIicBusTransaction* aTransaction)
+// Compares the indicated TIicBusTransaction with the expected content
+// Returns KErrNone if there is a match, KErrCorrupt otherwise.
+	{
+	TInt i;
+	// Check the transaction header
+	// Should contain the default header for SPI
+	TDes8* bufPtr = GetTransactionHeader(aTransaction);
+	if(bufPtr == NULL)
+		{
+		SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::CompareTransactionOne ERROR - NULL header\n"));
+		return KErrCorrupt;
+		}
+	TConfigSpiV01 *buf = (TConfigSpiV01 *)(bufPtr->Ptr());
+	if(buf->iWordWidth != ESpiWordWidth_8)
+		{
+		SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::CompareTransactionOne ERROR - Header wordwidth mis-match\n"));
+		return KErrCorrupt;
+		}
+	if(buf->iClkSpeedHz !=100000)
+		{
+		SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::CompareTransactionOne ERROR - Header clockspeed mis-match\n"));
+		return KErrCorrupt;
+		}
+	if(buf->iClkMode != ESpiPolarityLowRisingEdge)
+		{
+		SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::CompareTransactionOne ERROR - Header polarity mis-match\n"));
+		return KErrCorrupt;
+		}
+	if(buf->iTimeoutPeriod != 100)
+		{
+		SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::CompareTransactionOne ERROR - Header timeout mis-match\n"));
+		return KErrCorrupt;
+		}
+
+	SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::CompareTransactionOne header OK\n"));
+	
+	// Check the half-duplex transfer list
+	TIicBusTransfer* tfer = GetTransHalfDuplexTferPtr(aTransaction);
+	if(tfer == NULL)
+		{
+		SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::CompareTransactionOne ERROR - NULL half-duplex transfer\n"));
+		return KErrCorrupt;
+		}
+	// Process each transfer in the list
+	TInt8 dummy;
+
+	// tfer1 = new TIicBusTransfer(TIicBusTransfer::EMasterWrite,8,buf1);
+	// buf1 contains copy of TUint8 KTransOneTferOne[21] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20};
+	dummy=GetTferType(tfer);
+	if(dummy!=TIicBusTransfer::EMasterWrite)
+		{
+		SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::CompareTransactionOne ERROR - tfer1 type=%d\n"));
+		return KErrCorrupt;
+		}
+	dummy=GetTferBufGranularity(tfer);
+	if(dummy!=8)
+		{
+		SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::CompareTransactionOne ERROR - tfer1 granularity=%d\n",dummy));
+		return KErrCorrupt;
+		}
+	if((bufPtr = (TDes8*)GetTferBuffer(tfer)) == NULL)
+		{
+		SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::CompareTransactionOne ERROR - tfer1 buffer NULL\n"));
+		return KErrCorrupt;
+		}
+	for(i=0;i<21;++i)
+		{
+		if((*bufPtr)[i]!=i)
+			{
+			SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::CompareTransactionOne ERROR tfer1 buffer element %d has 0x%x\n",i,(*bufPtr)[i]));
+			return KErrCorrupt;
+			}
+		}
+	SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::CompareTransactionOne tfer1 OK\n"));
+
+
+	tfer=GetTferNextTfer(tfer);
+	// tfer2 = new TIicBusTransfer(TIicBusTransfer::EMasterRead,8,buf2);
+	// buf2 contains copy of TUint8 KTransOneTferTwo[8] = {17,18,19,20,21,22,23,24};
+	dummy=GetTferType(tfer);
+	if(dummy!=TIicBusTransfer::EMasterRead)
+		{
+		SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::CompareTransactionOne ERROR - tfer2 type=%d\n",dummy));
+		return KErrCorrupt;
+		}
+	dummy=GetTferBufGranularity(tfer);
+	if(dummy!=8)
+		{
+		SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::CompareTransactionOne ERROR - tfer2 granularity=%d\n",dummy));
+		return KErrCorrupt;
+		}
+	if((bufPtr = (TDes8*)GetTferBuffer(tfer)) == NULL)
+		{
+		SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::CompareTransactionOne ERROR - tfer2 buffer NULL\n"));
+		return KErrCorrupt;
+		}
+	for(i=0;i<8;++i)
+		{
+		if((*bufPtr)[i]!=(17+i))
+			{
+			SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::CompareTransactionOne ERROR tfer2 buffer element %d has 0x%x\n",i,(*bufPtr)[i]));
+			return KErrCorrupt;
+			}
+		}
+	SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::CompareTransactionOne tfer2 OK\n"));
+
+	tfer=GetTferNextTfer(tfer);
+	// tfer3 = new TIicBusTransfer(TIicBusTransfer::EMasterWrite,8,buf3);
+	// buf2 contains copy of TUint8 KTransOneTferThree[6] = {87,85,83,81,79,77};
+	dummy=GetTferType(tfer);
+	if(dummy!=TIicBusTransfer::EMasterWrite)
+		{
+		SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::CompareTransactionOne ERROR - tfer3 type=%d\n"));
+		return KErrCorrupt;
+		}
+	dummy=GetTferBufGranularity(tfer);
+	if(dummy!=8)
+		{
+		SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::CompareTransactionOne ERROR - tfer3 granularity=%d\n",dummy));
+		return KErrCorrupt;
+		}
+	if((bufPtr = (TDes8*)GetTferBuffer(tfer)) == NULL)
+		{
+		SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::CompareTransactionOne ERROR - tfer3 buffer NULL\n"));
+		return KErrCorrupt;
+		}
+	for(i=0;i<6;++i)
+		{
+		if((*bufPtr)[i]!=(87-(2*i)))
+			{
+			SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::CompareTransactionOne ERROR tfer3 buffer element %d has 0x%x\n",i,(*bufPtr)[i]));
+			return KErrCorrupt;
+			}
+		}
+	SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::CompareTransactionOne tfer3 OK\n"));
+
+	// Shouldn't be any more transfers in the half duplex list
+	if((tfer=GetTferNextTfer(tfer))!=NULL)
+		{
+		SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::CompareTransactionOne ERROR - tfer3 iNext=0x%x\n",tfer));
+		return KErrCorrupt;
+		}
+	SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::CompareTransactionOne half-duplex transfer OK\n"));
+
+	// The full duplex transfer should be represented by a NULL pointer
+	if((tfer=GetTransFullDuplexTferPtr(aTransaction))!=NULL)
+		{
+		SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::CompareTransactionOne ERROR - full duplex pointer=0x%x\n",tfer));
+		return KErrCorrupt;
+		}
+	SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::CompareTransactionOne full duplex pointer is NULL (OK)\n"));
+
+	// Synchronous transaction, so check the callback pointer is NULL
+	TIicBusCallback* dumCb = NULL;
+	dumCb=GetTransCallback(aTransaction);
+	if(dumCb!=NULL)
+		{
+		SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::CompareTransactionOne ERROR - callback pointer=0x%x\n",dumCb));
+		return KErrCorrupt;
+		}
+	SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::CompareTransactionOne callback pointer is NULL (OK)\n"));
+
+	// Check the transaction flags are set to zero
+	TUint8 dumFlags;
+	dumFlags=GetTransFlags(aTransaction);
+	if(dumFlags!=0)
+		{
+		SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::CompareTransactionOne ERROR - flags=0x%x\n",dumFlags));
+		return KErrCorrupt;
+		}
+	SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::CompareTransactionOne flags are zero (OK)\n"));
+
+	return KErrNone;
+	}
+
+
+// The THwCallbackFunc gets called if the hardware preparation completes successfully.
+void THwCallbackFunc(TAny* aPtr)
+	{
+	SPI_PRINT(("Hardware preparation completed, calling the callback function"));
+	DSimulatedIicBusChannelMasterSpi* aChanMasterSpi=(DSimulatedIicBusChannelMasterSpi* )aPtr;
+	TInt r = aChanMasterSpi->DoSimulatedTransaction();
+	((DSimulatedIicBusChannelMasterSpi*)aChanMasterSpi)->CompleteReq(r);
+	}
+
+TInt DSimulatedIicBusChannelMasterSpi::DoSimulatedTransaction()
+	{
+	TInt r = AsynchStateMachine(EHwTransferDone);
+	if(iTimeoutTimer.Cancel() == FALSE)
+		{
+		SPI_PRINT(("timer is not cancelled"));
+		}
+	return r;
+	}
+
+TInt DSimulatedIicBusChannelMasterSpi::DoHwPreparation()
+	{
+	SPI_PRINT(("Preparing hardware for the transaction"));
+	
+	TInt r = KErrNone;
+	// The hardware preparation can either complete successfully or fail. 
+	// If successful, invoke the callback function of THwDoneCallBack
+	// if not, execute the timeout machanism
+	// Currently DoHwPreparation is just a simple function. It should be more complicated 
+	// for the real hardware.
+	switch(iTestState)
+		{
+		case (ETestSlaveTimeOut):
+			{
+			// In the timeout test, do nothing until the timeout callback function is invoked.
+			SPI_PRINT(("Simulating the timeout process."));
+			break;
+			}
+		case (ETestNone):
+			{
+			// Pretend the hardware preparation's been done, and a callback function is invoked to call 
+			// the Asynchronous State Machine
+			SPI_PRINT(("Hardware preparing work is executing normally."));
+			iCb->Enque();
+			break;
+			}
+		default:
+			{
+			SPI_PRINT(("Not a valid test."));
+			r = KErrNotSupported;
+			break;
+			}	
+		}
+	
+	return r; 
+	}
+
+// Gateway function for PSL implementation, invoked for DFC processing
+TInt DSimulatedIicBusChannelMasterSpi::DoRequest(TIicBusTransaction* aTransaction)
+	{
+	SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::DoRequest invoked with aTransaction=0x%x\n",aTransaction));
+	
+	TInt r = KErrNone;
+	iCurrTrans=aTransaction;
+	
+	// Check if the Asynchronous State Machine is available. If not, then return KErrInUse. 
+	// This is used to stop the second transaction executing if the machine has already been holding 
+	// by a transaction. However, this situation cannot be tested because of the malfunction in PIL
+	if(iChannelState!= EIdle)
+		return KErrInUse;
+	
+	iChannelState = EBusy;
+#ifdef IIC_INSTRUMENTATION_MACRO
+	IIC_MPROCESSTRANS_START_PSL_TRACE;
+#endif
+	r = ProcessTrans(aTransaction);
+
+	SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::DoRequest - exiting\n"));
+	return r;
+	}
+
+TInt DSimulatedIicBusChannelMasterSpi::ProcessTrans(TIicBusTransaction* aTransaction)
+		{
+		TInt r=KErrNone;
+		
+		switch(iTestState)
+			{
+			case(ETestWaitTransOne):
+				{
+				// The transaction received should exhibit the expected data
+				// Return KErrArgument if this is not the case
+				// The timer should be started at the beginning of every transaction
+				// For simplicity, we omit the timer here. 
+				r=CompareTransactionOne(iCurrTrans);
+				iChannelState = EIdle;
+				CompleteRequest(KErrNone);
+				break;
+				}
+			case(ETestSlaveTimeOut):
+				{
+				// Test the timeout funciton
+				SPI_PRINT(("Test the slave timeout function\n"));
+				
+				// Simulate a timeout 
+				// Start a timer and then wait for the Slave response to timeout
+				// A real bus would use its own means to identify a timeout
+				TInt aTime=1000000/NKern::TickPeriod();
+				r = StartSlaveTimeOutTimer(aTime);
+				if(r != KErrNone)
+					return r;
+				r = DoHwPreparation();
+				break;
+				}
+			case(ETestWaitPriorityTest):
+				{	
+				static TInt TranCount = 0;
+				if(TranCount >= KPriorityTestNum) return KErrUnknown;
+				// block the channel
+				while(IsRequestDelayed(this))
+					{
+					SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::DoRequest - starting Sleep...\n"));
+					NKern::Sleep(1000);	// 1000 is arbitrary
+					SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::DoRequest - completed Sleep, check if still delayed\n"));
+					}; 
+				// get transaction header			
+				TDes8* bufPtr = GetTransactionHeader(aTransaction);
+				if(bufPtr == NULL)
+				{
+				SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::DoRequest ERROR - NULL header\n"));
+				return KErrCorrupt;
+				}
+
+				if(TranCount == 0)
+					{			
+					// ignore the blocking transaction
+					TranCount++;
+					}
+				else
+					{
+					// store transaction header
+					iPriorityTestResult[TranCount++] = (*bufPtr)[0];
+					SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::DoRequest Priority test transaction no.:%d Priority:%d", 
+						(*bufPtr)[0], aTransaction->iKey));
+					}
+				iChannelState = EIdle;
+				CompleteRequest(KErrNone);
+				if(TranCount == KPriorityTestNum) iPriorityTestDone = ETrue;
+				break;
+				}
+
+
+
+			case(ETestNone):
+				{
+				SPI_PRINT(("Nothing to be tested, just do the usual transaction"));
+				
+				// Start the timer on the Slave response. 
+				// Since no timeout, this timer will be cancelled in the THwCallbackFunc
+				r = StartSlaveTimeOutTimer(100000);
+				if(r != KErrNone)
+					return r;
+				// Use a class THwDoneCallBack derived from TDfc to trigger the asynchronous state machine 
+				// when the hardware preparation completes successfully. 
+				// The priority is set with an arbitrary number 5
+				iCb = new THwDoneCallBack(THwCallbackFunc, this, iDynamicDfcQ, 5);
+				r = DoHwPreparation(); 
+				break;
+				}
+			default:
+				{
+				SPI_PRINT(("Test status not matched"));
+				return KErrNotSupported;
+				}
+			}
+
+		return r;
+		}
+	
+	
+TInt DSimulatedIicBusChannelMasterSpi::AsynchStateMachine(TInt aReason)
+	{
+	TInt r=KErrNone; 
+	
+	// The asynchronous state machine has two states, it could either be idle or busy.
+	// Initially, it's in idle state. When a user queues a transaction, the hardware preparation starts
+	// and the state changes to busy. After the hardware preparation completes, either successfully or not, 
+	// the state machine will do the corresponding work for the transaction and then goes back to the idle state.  
+	switch(iChannelState)
+		{
+		case(EIdle):
+			{
+			 return KErrGeneral;
+			}
+		case (EBusy):
+			{
+			switch(aReason)
+				{
+				case(EHwTransferDone):
+					{
+								
+					// Simulate processing - for now, do nothing!
+					//
+					SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::AsynchStateMachine aTransaction->iHeader=0x%x\n",GetTransactionHeader(iCurrTrans)));
+					SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::AsynchStateMachine aTransaction->iHalfDuplexTrans=0x%x\n",GetTransHalfDuplexTferPtr(iCurrTrans)));
+					SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::AsynchStateMachine aTransaction->iFullDuplexTrans=0x%x\n",GetTransFullDuplexTferPtr(iCurrTrans)));
+					SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::AsynchStateMachine aTransaction->iCallback=0x%x\n",GetTransCallback(iCurrTrans)));
+					SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::AsynchStateMachine aTransaction->iFlags=0x%x\n",GetTransFlags(iCurrTrans)));
+
+					SPI_PRINT(("\nDSimulatedIicBusChannelMasterSpi::AsynchStateMachine, iHeader info \n"));
+					TDes8* bufPtr = GetTransactionHeader(iCurrTrans);
+					if(bufPtr == NULL)
+						{
+						SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::AsynchStateMachine ERROR - NULL header\n"));
+						return KErrCorrupt;
+						}
+					TConfigSpiV01 *buf = (TConfigSpiV01 *)(bufPtr->Ptr());
+					SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::AsynchStateMachine, header word width=0x%x\n",buf->iWordWidth));
+					SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::AsynchStateMachine, header clock speed=0x%x\n",buf->iClkSpeedHz));
+					SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::AsynchStateMachine, header clock mode=0x%x\n",buf->iClkMode));
+					SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::AsynchStateMachine, header timeout period=0x%x\n",buf->iTimeoutPeriod));
+					SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::AsynchStateMachine, header endianness=0x%x\n",buf->iEndianness));
+					SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::AsynchStateMachine, header bit order=0x%x\n",buf->iBitOrder));
+					SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::AsynchStateMachine, header wait cycles=0x%x\n",buf->iTransactionWaitCycles));
+					SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::AsynchStateMachine, header Slave select pin mode=0x%x\n",buf->iSSPinActiveMode));
+					(void)buf;	// Silence compiler when SPI_PRINT not used
+							
+					SPI_PRINT(("\nDSimulatedIicBusChannelMasterSpi::AsynchStateMachine, iHalfDuplexTrans info \n"));
+					TIicBusTransfer* halfDuplexPtr=GetTransHalfDuplexTferPtr(iCurrTrans);
+					while(halfDuplexPtr != NULL)
+						{
+						SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::AsynchStateMachine transfer type=0x%x\n",GetTferType(halfDuplexPtr)));
+						SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::AsynchStateMachine granularity=0x%x\n",GetTferBufGranularity(halfDuplexPtr)));
+						SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::AsynchStateMachine transfer buffer=0x%x\n",GetTferBuffer(halfDuplexPtr)));
+						SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::AsynchStateMachine next transfer =0x%x\n",GetTferNextTfer(halfDuplexPtr)));
+						halfDuplexPtr=GetTferNextTfer(halfDuplexPtr);
+						}
+					SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::AsynchStateMachine - End of iHalfDuplexTrans info"));
+					
+					while(IsRequestDelayed(this))
+						{
+						SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::AsynchStateMachine - starting Sleep...\n"));
+						NKern::Sleep(1000);	// 1000 is arbitrary
+						SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::AsynchStateMachine - completed Sleep, check if still delayed\n"));
+						}; 
+				
+					iChannelState=EIdle; 
+					delete iCb;
+					break;
+					}
+				case(ETimeExpired):
+					{
+					SPI_PRINT(("Time expired, the Asynchrnous State Machine will be Idle again, and wait for the next request."));
+					iChannelState=EIdle;
+					r = KErrTimedOut; 
+					break;
+					}
+				default:
+					{
+					SPI_PRINT(("Request can not be handled, return error code."));
+					return KErrNotSupported;
+					}
+				}
+			break;
+			}
+		default:
+			{
+			SPI_PRINT(("No matched state"));
+			return KErrGeneral;
+			}
+		}
+	return r; 
+	}
+
+
+TBool DSimulatedIicBusChannelMasterSpi::IsRequestDelayed(DSimulatedIicBusChannelMasterSpi* aChan)
+	{
+	SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::IsRequestDelayed invoked for aChan=0x%x\n",aChan));
+	return aChan->iReqDelayed;
+	}
+
+void DSimulatedIicBusChannelMasterSpi::SetRequestDelayed(DSimulatedIicBusChannelMasterSpi* aChan,TBool aDelay) 
+	{
+	SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::SetRequestDelayed invoked for aChan=0x%x, with aDelay=0x%d\n",aChan,aDelay));
+	aChan->iReqDelayed=aDelay;
+	}
+
+TInt DSimulatedIicBusChannelMasterSpi::StaticExtension(TUint aFunction, TAny* aParam1, TAny* aParam2)
+	{
+	SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::StaticExtension\n"));
+#ifdef IIC_INSTRUMENTATION_MACRO
+	IIC_MSTATEXT_START_PSL_TRACE;
+#endif
+	(void)aParam1;
+	(void)aParam2;
+	TInt r = KErrNone;
+	// Test values of aFunction were shifted left one place by the (test) client driver
+	// and for Slave values the two msb were cleared
+	// Return to its original value.
+	if(aFunction>KTestControlIoPilOffset)
+		aFunction >>= 1;
+	switch(aFunction)
+		{
+		case(RBusDevIicClient::ECtlIoDumpChan):
+			{
+#ifdef _DEBUG
+			DumpChannel();
+#endif
+			break;
+			}
+		case(RBusDevIicClient::ECtlIoBlockReqCompletion):
+			{
+			SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::Blocking request completion\n"));
+			SetRequestDelayed(this, ETrue);
+			break;
+			}
+		case(RBusDevIicClient::ECtlIoUnblockReqCompletion):
+			{
+			SPI_PRINT(("DSimulatedIicBusChannelMasterSpi::Unlocking request completion\n"));
+			SetRequestDelayed(this, EFalse);
+			break;
+			}
+		case(RBusDevIicClient::ECtlIoDeRegChan):
+			{
+#ifdef IIC_INSTRUMENTATION_MACRO
+	IIC_DEREGISTERCHAN_START_PSL_TRACE;
+#endif
+			SPI_PRINT(("DSimulatedIicBusChannelMasterSpi: deregister channel\n"));
+#ifndef STANDALONE_CHANNEL
+			r=DIicBusController::DeRegisterChannel(this);
+#endif
+
+#ifdef IIC_INSTRUMENTATION_MACRO
+	IIC_DEREGISTERCHAN_END_PSL_TRACE;
+#endif
+			break;
+			}
+
+		case(RBusDevIicClient::ECtlIoPriorityTest):
+			{
+			SPI_PRINT(("DSimulatedIicBusChannelMasterSpi: warned to expect priority test\n"));
+			iPriorityTestDone = EFalse;
+			iTestState=ETestWaitPriorityTest;
+			break;
+			}
+		case(RBusDevIicClient::EGetTestResult):
+			{
+			if(!iPriorityTestDone) return KErrNotReady;
+			
+			SPI_PRINT(("DSimulatedIicBusChannelMasterSpi: get priority test order\n"));
+
+			//iPriorityTestResult[0] is the blocking transaction, ignore it. start from entry 1.
+			for(TInt i=1; i<KPriorityTestNum; i++)
+				{
+				if(iPriorityTestResult[i]!=(KPriorityTestNum-i-1))
+					{
+					r = KErrGeneral;
+					break;
+					}
+				}
+				r = KErrNone;
+			break;
+			}
+
+		case(RBusDevIicClient::ECtlIoTracnOne):
+			{
+			SPI_PRINT(("DSimulatedIicBusChannelMasterSpi: warned to expect Transaction One\n"));
+			iTestState=ETestWaitTransOne;
+			break;
+			}
+		case(RBusDevIicClient::ECtlIoNone):
+			{
+			SPI_PRINT(("DSimulatedIicBusChannelMasterSpi: terminate ControlIO state\n"));
+			iTestState=ETestNone;
+			break;
+			}
+		case(RBusDevIicClient::ECtlIoSetTimeOutFlag):
+			{
+			SPI_PRINT(("DSimulatedIicBusChannelMasterSpi: test slave time out\n"));
+			iTestState=ETestSlaveTimeOut;
+			break;
+			}
+		default:
+			{
+			Kern::Printf("aFunction %d is not recognised \n",aFunction);
+			r=KErrNotSupported;
+			}
+		}
+#ifdef IIC_INSTRUMENTATION_MACRO
+	IIC_MSTATEXT_END_PSL_TRACE;
+#endif		
+	return r;
+	}
+
+void DSimulatedIicBusChannelMasterSpi::CompleteReq(TInt aResult)
+	{
+#ifdef IIC_INSTRUMENTATION_MACRO
+	IIC_MPROCESSTRANS_END_PSL_TRACE;
+#endif
+	CompleteRequest(aResult);
+	}
+
+
+void DSimulatedIicBusChannelSlaveSpi::SlaveAsyncSimCallback(TAny* aPtr)
+	{
+	SPI_PRINT(("SlaveAsyncSimCallback\n"));
+	DSimulatedIicBusChannelSlaveSpi* channel = (DSimulatedIicBusChannelSlaveSpi*)aPtr;
+	TInt r=KErrNone;	// Just simulate successfull capture
+#ifdef IIC_INSTRUMENTATION_MACRO
+	IIC_SCAPTCHANASYNC_END_PSL_TRACE;
+#endif
+	channel->ChanCaptureCb(r);
+	}
+
+#ifdef STANDALONE_CHANNEL
+EXPORT_C
+#endif
+	DSimulatedIicBusChannelSlaveSpi::DSimulatedIicBusChannelSlaveSpi(const DIicBusChannel::TBusType aBusType, const DIicBusChannel::TChannelDuplex aChanDuplex)
+	: DIicBusChannelSlave(aBusType,aChanDuplex,0), // 0 to be ignored by base class
+	iSlaveTimer(SlaveAsyncSimCallback,this)
+	{
+	SPI_PRINT(("DSimulatedIicBusChannelSlaveSpi::DSimulatedIicBusChannelSlaveSpi, aBusType=%d,aChanDuplex=%d\n",aBusType,aChanDuplex));
+#ifndef STANDALONE_CHANNEL
+	iChannelNumber = AssignChanNum();
+#endif
+	SPI_PRINT(("DSimulatedIicBusChannelSlaveSpi::DSimulatedIicBusChannelSlaveSpi, iChannelNumber=%d\n",iChannelNumber));
+	}
+
+TInt DSimulatedIicBusChannelSlaveSpi::CaptureChannelPsl(TDes8* /*aConfigHdr*/, TBool aAsynch)
+	{
+	SPI_PRINT(("DSimulatedIicBusChannelSlaveSpi::CaptureChannelPsl, aAsynch=%d\n",aAsynch));
+	TInt r = KErrNone;
+	if(aAsynch)
+		{
+#ifdef IIC_INSTRUMENTATION_MACRO
+	IIC_SCAPTCHANASYNC_START_PSL_TRACE;
+#endif
+		// To simulate an asynchronous operation, just set a timer to expire
+		iSlaveTimer.OneShot(1000, ETrue); // Arbitrary timeout - expiry executes callback in context of DfcThread1
+		}
+	else
+		{
+#ifdef IIC_INSTRUMENTATION_MACRO
+	IIC_SCAPTCHANSYNC_START_PSL_TRACE;
+#endif
+		// PSL processing would happen here ...
+		// Expected to include implementation of the header configuration information 
+#ifdef IIC_INSTRUMENTATION_MACRO
+	IIC_SCAPTCHANSYNC_END_PSL_TRACE;
+#endif
+		}
+	SPI_PRINT(("DSimulatedIicBusChannelSlaveI2c::CaptureChanSync ... no real processing to do \n"));
+
+	return r;
+	}
+
+TInt DSimulatedIicBusChannelSlaveSpi::CheckHdr(TDes8* /*aHdr*/)
+	{
+	SPI_PRINT(("DSimulatedIicBusChannelSlaveSpi::CheckHdr\n"));
+	return KErrNone;
+	}
+
+TInt DSimulatedIicBusChannelSlaveSpi::DoCreate()
+	{
+	SPI_PRINT(("DSimulatedIicBusChannelSlaveSpi::DoCreate\n"));
+	TInt r=Init();	// PIL Base class initialisation
+	return r;
+	}
+
+TInt DSimulatedIicBusChannelSlaveSpi::DoRequest(TInt /*aTrigger*/)
+	{
+	SPI_PRINT(("DSimulatedIicBusChannelSlaveSpi::DoRequest\n"));
+	return KErrNotSupported; 
+	}
+
+void DSimulatedIicBusChannelSlaveSpi::ProcessData(TInt /*aTrigger*/, TIicBusSlaveCallback*  /*aCb*/)
+	{
+	SPI_PRINT(("DSimulatedIicBusChannelSlaveSpi::ProcessData\n"));
+	}
+
+TInt DSimulatedIicBusChannelSlaveSpi::StaticExtension(TUint aFunction, TAny* aParam1, TAny* aParam2)
+	{
+	SPI_PRINT(("DSimulatedIicBusChannelSlaveSpi::StaticExtension\n"));
+#ifdef IIC_INSTRUMENTATION_MACRO
+	IIC_SSTATEXT_START_PSL_TRACE;
+#endif
+	(void)aParam1;
+	(void)aParam2;
+	// Test values of aFunction were shifted left one place by the (test) client driver
+	// and for Slave values the two msb were cleared
+	// Return to its original value.
+	if(aFunction>KTestControlIoPilOffset)
+		{
+		aFunction |= 0xC0000000;
+		aFunction >>= 1;
+		}
+	TInt r = KErrNone;
+	switch(aFunction)
+		{
+		case(RBusDevIicClient::ECtlIoDumpChan):
+			{
+#ifdef _DEBUG
+			DumpChannel();
+#endif
+			break;
+			}
+		default:
+			{
+			Kern::Printf("aFunction %d is not recognised \n",aFunction);
+			r=KErrNotSupported;
+			}
+		}
+
+#ifdef IIC_INSTRUMENTATION_MACRO
+	IIC_SSTATEXT_START_PSL_TRACE;
+#endif
+	(void)aFunction;
+	return r;
+	}
+
+
+
+
+
+